@desplega.ai/agent-swarm 1.103.0 → 1.104.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 +2 -0
- package/dist/{actions-7txktrdj.js → actions-2expzt47.js} +6 -6
- package/dist/{app-xm3xsdye.js → app-dr8hwx7z.js} +3 -3
- package/dist/{assistant-qpv63wk6.js → assistant-9rhgsw7v.js} +9 -10
- package/dist/{boot-reembed-chxhrwv8.js → boot-reembed-3q1aywnz.js} +5 -4
- package/dist/{boot-reembed-9cxqka3e.js → boot-reembed-9kt97g1z.js} +4 -3
- package/dist/{boot-scrub-logs-8qtfkcz8.js → boot-scrub-logs-vskq108e.js} +2 -2
- package/dist/{cli-fedn86nz.js → cli-0jw6j755.js} +8 -3
- package/dist/{cli-yeemwevj.js → cli-23zk7xqy.js} +20 -16
- package/dist/{cli-v9283nma.js → cli-2g9jf9ek.js} +1 -1
- package/dist/{cli-rvae030h.js → cli-2hap19dv.js} +3 -3
- package/dist/{cli-wjyyv518.js → cli-3j01d33e.js} +9 -14
- package/dist/{cli-8hyv6c2v.js → cli-54h5daha.js} +41 -23
- package/dist/{cli-fygaw191.js → cli-5pf0b84v.js} +2 -2
- package/dist/{cli-m8f6qzck.js → cli-7v4y3hyd.js} +1 -1
- package/dist/{cli-fwxdt7kt.js → cli-d4z1csms.js} +30 -5
- package/dist/{cli-jt9d9fjw.js → cli-e7bwjntj.js} +1 -1
- package/dist/{cli-s14sb64w.js → cli-etvgz5x8.js} +5 -7
- package/dist/{cli-2qynerth.js → cli-gj2n2ec1.js} +1 -1
- package/dist/{cli-dz3d6zjg.js → cli-nzc0h54v.js} +121 -2
- package/dist/{cli-8w95v19d.js → cli-p4cj4vhc.js} +351 -24
- package/dist/{cli-xmtsan9k.js → cli-q5tshxd6.js} +1 -1
- package/dist/{http-zts4haq7.js → cli-qvzgncd8.js} +83966 -76422
- package/dist/{cli-4fnp2tc3.js → cli-s42f54ja.js} +1 -1
- package/dist/{cli-krvxq8bc.js → cli-t9v14cnd.js} +23 -4
- package/dist/{cli-gzepjz54.js → cli-v1syqkcb.js} +900 -352
- package/dist/{cli-ksq38x4n.js → cli-w1nfskkg.js} +2 -2
- package/dist/{cli-ns0r7mkr.js → cli-y9p3e94h.js} +3 -3
- package/dist/{cli-85pf4z38.js → cli-yjt8a36k.js} +3 -3
- package/dist/{cli-yfwwjeft.js → cli-yvektv79.js} +1 -1
- package/dist/{cli-kk51f3tf.js → cli-zaxksbgj.js} +5 -5
- package/dist/{cli-rttgde5f.js → cli-zghef0em.js} +1 -1
- package/dist/cli.js +10 -10
- package/dist/{commands-aqn63mcw.js → commands-wfrkef57.js} +2 -2
- package/dist/{db-azrvwsnj.js → db-c42pxt7h.js} +2 -2
- package/dist/{handlers-hf61har3.js → handlers-n36zkfvx.js} +10 -12
- package/dist/{hook-306p3yz4.js → hook-gw3vhv6s.js} +7 -5
- package/dist/http-59ygpn2h.js +17263 -0
- package/dist/{index-h2yqjyk0.js → index-881c1baf.js} +9 -8
- package/dist/{index-29vg51x6.js → index-jca7jdpt.js} +23 -10
- package/dist/{index-bfh9hgek.js → index-xf6fp4y1.js} +5 -5
- package/dist/{index-3c651yfk.js → index-xz8vaa5c.js} +14 -11
- package/dist/{keepalive-a0dg5pds.js → keepalive-mj4302vw.js} +4 -4
- package/dist/{lead-7mcxedkc.js → lead-qm0xjvkv.js} +19 -19
- package/dist/{maintenance-mrzqd53t.js → maintenance-xppxbe4t.js} +5 -4
- package/dist/{onboard-4dkpv9wa.js → onboard-ejx6yxh8.js} +2 -2
- package/dist/{otel-impl-jt7gpyp9.js → otel-impl-zs5exkpk.js} +1 -1
- package/dist/{pricing-refresh-xqnzh8dt.js → pricing-refresh-nqyf8bkb.js} +4 -4
- package/dist/{seed-pricing-56tjm1fj.js → seed-pricing-w3x550cj.js} +3 -3
- package/dist/{setup-tbwk8j10.js → setup-7729ktfj.js} +2 -2
- package/dist/{worker-e03za92t.js → worker-4ttemwhw.js} +19 -19
- package/openapi.json +90 -4
- package/package.json +3 -3
- package/src/be/memory/constants.ts +6 -0
- package/src/be/memory/providers/sqlite-store.ts +468 -71
- package/src/be/memory/raters/retrieval.ts +4 -2
- package/src/be/memory/reranker.ts +5 -2
- package/src/be/memory/retrieval-store.ts +2 -0
- package/src/be/memory/types.ts +46 -0
- package/src/be/migrations/099_memory_structured_key_versioning.sql +41 -0
- package/src/be/migrations/100_memory_retrieval_source.sql +8 -0
- package/src/be/migrations/101_script_connections.sql +67 -0
- package/src/be/script-connections.ts +744 -0
- package/src/be/script-credential-broker.ts +38 -0
- package/src/be/scripts/typecheck.ts +23 -2
- package/src/be/seed-scripts/catalog/boot-triage.inline.ts +16 -4
- package/src/be/seed-scripts/catalog/boot-triage.ts +16 -4
- package/src/commands/runner.ts +8 -6
- package/src/heartbeat/heartbeat.ts +42 -1
- package/src/heartbeat/index.ts +7 -1
- package/src/http/memory.ts +127 -14
- package/src/http/scripts.ts +15 -14
- package/src/scripts-runtime/api-client.ts +100 -0
- package/src/scripts-runtime/api-types.ts +45 -0
- package/src/scripts-runtime/credential-broker/README.md +40 -0
- package/src/scripts-runtime/credential-broker/broker.ts +51 -0
- package/src/scripts-runtime/credential-broker/default-bindings.ts +19 -0
- package/src/scripts-runtime/credential-broker/fetch-patch.ts +102 -0
- package/src/scripts-runtime/credential-broker/index.ts +17 -0
- package/src/scripts-runtime/credential-broker/store.ts +72 -0
- package/src/scripts-runtime/credential-broker/types.ts +54 -0
- package/src/scripts-runtime/ctx.ts +11 -1
- package/src/scripts-runtime/egress-secrets.ts +14 -76
- package/src/scripts-runtime/eval-harness.ts +1 -1
- package/src/scripts-runtime/executors/types.ts +5 -5
- package/src/scripts-runtime/loader.ts +6 -1
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +11 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +11 -0
- package/src/server.ts +6 -0
- package/src/tests/credential-broker.test.ts +281 -0
- package/src/tests/heartbeat.test.ts +239 -0
- package/src/tests/memory-edit.test.ts +177 -0
- package/src/tests/memory-hybrid.test.ts +212 -0
- package/src/tests/runner-repo-autostash.test.ts +39 -8
- package/src/tests/script-connections.test.ts +360 -0
- package/src/tests/scripts-http.test.ts +16 -10
- package/src/tests/scripts-runtime-secret-egress.test.ts +26 -5
- package/src/tests/swarm-config-reserved-keys.test.ts +23 -0
- package/src/tests/update-schedule-mcp-tool.test.ts +83 -4
- package/src/tools/credential-bindings/index.ts +1 -0
- package/src/tools/credential-bindings/tool.ts +238 -0
- package/src/tools/memory-edit.ts +148 -0
- package/src/tools/memory-search.ts +17 -10
- package/src/tools/schedules/delete-schedule.ts +18 -8
- package/src/tools/schedules/update-schedule.ts +4 -9
- package/src/tools/script-connections/index.ts +1 -0
- package/src/tools/script-connections/tool.ts +167 -0
- package/src/tools/swarm-config/delete-config.ts +5 -0
- package/src/tools/swarm-config/set-config.ts +23 -1
- package/src/tools/tool-config.ts +6 -1
- package/src/types.ts +6 -0
- package/src/workflows/executors/swarm-script.ts +2 -0
- package/templates/community/dora-metrics/PLAYBOOK.md +294 -0
- package/templates/community/dora-metrics/README.md +39 -0
- package/templates/community/dora-metrics/lead-prompt.md +56 -0
- package/templates/community/dora-metrics/report.mjs +393 -0
- package/templates/community/dora-metrics/run.sh +113 -0
- package/templates/schedules/weekly-dora-metrics/config.json +13 -0
- package/templates/schedules/weekly-dora-metrics/content.md +61 -0
- package/dist/cli-2307phk1.js +0 -24223
- package/dist/cli-2deg0cen.js +0 -120
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getAgentById } from "@/be/db";
|
|
4
|
+
import {
|
|
5
|
+
disableCredentialBinding,
|
|
6
|
+
importLegacyCredentialBindings,
|
|
7
|
+
listRelationalCredentialBindings,
|
|
8
|
+
upsertCredentialBinding,
|
|
9
|
+
} from "@/be/script-connections";
|
|
10
|
+
import {
|
|
11
|
+
CredentialBindingSchema,
|
|
12
|
+
placeholderForConfigKey,
|
|
13
|
+
} from "@/scripts-runtime/credential-broker";
|
|
14
|
+
import { createToolRegistrar } from "@/tools/utils";
|
|
15
|
+
|
|
16
|
+
const credentialBindingsOutputSchema = z.object({
|
|
17
|
+
yourAgentId: z.string().uuid().optional(),
|
|
18
|
+
success: z.boolean(),
|
|
19
|
+
message: z.string(),
|
|
20
|
+
bindings: z.array(CredentialBindingSchema),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const credentialBindingsInputSchema = z.object({
|
|
24
|
+
action: z
|
|
25
|
+
.enum(["list", "upsert", "disable", "import-legacy"])
|
|
26
|
+
.describe("List, add/update, disable, or import legacy JSON bindings."),
|
|
27
|
+
id: z.string().uuid().optional(),
|
|
28
|
+
configKey: z.string().min(1).max(255).optional(),
|
|
29
|
+
allowedHosts: z.array(z.string().min(1)).min(1).optional(),
|
|
30
|
+
headerTemplate: z.string().min(1).optional(),
|
|
31
|
+
queryTemplate: z.string().min(1).optional(),
|
|
32
|
+
scope: z.enum(["global", "agent", "repo"]).default("global").optional(),
|
|
33
|
+
scopeId: z.string().uuid().nullable().optional(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
37
|
+
createToolRegistrar(server)(
|
|
38
|
+
"credential-bindings",
|
|
39
|
+
{
|
|
40
|
+
title: "Credential Bindings",
|
|
41
|
+
description:
|
|
42
|
+
"Lead-only management for scripts-runtime credential broker bindings. Bindings map config keys to allowed egress hosts; scripts consume them only through fetch-layer placeholder substitution.",
|
|
43
|
+
annotations: { idempotentHint: true },
|
|
44
|
+
inputSchema: credentialBindingsInputSchema,
|
|
45
|
+
outputSchema: credentialBindingsOutputSchema,
|
|
46
|
+
},
|
|
47
|
+
async (args, requestInfo) => {
|
|
48
|
+
if (!requestInfo.agentId) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: 'Agent ID not found. Set the "X-Agent-ID" header.' }],
|
|
51
|
+
structuredContent: {
|
|
52
|
+
success: false,
|
|
53
|
+
message: 'Agent ID not found. Set the "X-Agent-ID" header.',
|
|
54
|
+
bindings: [],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
60
|
+
if (!agent?.isLead) {
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: "text", text: "Only the lead can manage credential bindings." }],
|
|
63
|
+
structuredContent: {
|
|
64
|
+
yourAgentId: requestInfo.agentId,
|
|
65
|
+
success: false,
|
|
66
|
+
message: "Only the lead can manage credential bindings.",
|
|
67
|
+
bindings: [],
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const bindings = listRelationalCredentialBindings({ includeInactive: true });
|
|
73
|
+
|
|
74
|
+
if (args.action === "list") {
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text:
|
|
80
|
+
bindings.length === 0
|
|
81
|
+
? "No configured credential bindings."
|
|
82
|
+
: `Found ${bindings.length} credential binding(s).`,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
structuredContent: {
|
|
86
|
+
yourAgentId: requestInfo.agentId,
|
|
87
|
+
success: true,
|
|
88
|
+
message:
|
|
89
|
+
bindings.length === 0
|
|
90
|
+
? "No configured credential bindings."
|
|
91
|
+
: `Found ${bindings.length} credential binding(s).`,
|
|
92
|
+
bindings,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (args.action === "import-legacy") {
|
|
98
|
+
const imported = importLegacyCredentialBindings();
|
|
99
|
+
const nextBindings = listRelationalCredentialBindings({ includeInactive: true });
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: `Imported ${imported} legacy credential binding(s).` }],
|
|
102
|
+
structuredContent: {
|
|
103
|
+
yourAgentId: requestInfo.agentId,
|
|
104
|
+
success: true,
|
|
105
|
+
message: `Imported ${imported} legacy credential binding(s).`,
|
|
106
|
+
bindings: nextBindings,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (args.action === "disable") {
|
|
112
|
+
const disabled = args.id ? disableCredentialBinding(args.id) : null;
|
|
113
|
+
if (!disabled) {
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: "Credential binding id not found." }],
|
|
116
|
+
structuredContent: {
|
|
117
|
+
yourAgentId: requestInfo.agentId,
|
|
118
|
+
success: false,
|
|
119
|
+
message: "Credential binding id not found.",
|
|
120
|
+
bindings,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const nextBindings = listRelationalCredentialBindings({ includeInactive: true });
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: `Credential binding ${disabled.configKey} disabled.` }],
|
|
128
|
+
structuredContent: {
|
|
129
|
+
yourAgentId: requestInfo.agentId,
|
|
130
|
+
success: true,
|
|
131
|
+
message: `Credential binding ${disabled.configKey} disabled.`,
|
|
132
|
+
bindings: nextBindings,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!args.configKey) {
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: "text", text: "configKey is required for upsert." }],
|
|
140
|
+
structuredContent: {
|
|
141
|
+
yourAgentId: requestInfo.agentId,
|
|
142
|
+
success: false,
|
|
143
|
+
message: "configKey is required for upsert.",
|
|
144
|
+
bindings,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const scope = args.scope ?? "global";
|
|
150
|
+
const scopeId = scope === "global" ? null : (args.scopeId ?? null);
|
|
151
|
+
if (scope !== "global" && !scopeId) {
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: `scopeId is required for ${scope} bindings.` }],
|
|
154
|
+
structuredContent: {
|
|
155
|
+
yourAgentId: requestInfo.agentId,
|
|
156
|
+
success: false,
|
|
157
|
+
message: `scopeId is required for ${scope} bindings.`,
|
|
158
|
+
bindings,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!args.allowedHosts || (!args.headerTemplate && !args.queryTemplate)) {
|
|
164
|
+
return {
|
|
165
|
+
content: [
|
|
166
|
+
{
|
|
167
|
+
type: "text",
|
|
168
|
+
text: "allowedHosts and at least one of headerTemplate or queryTemplate are required for upsert.",
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
structuredContent: {
|
|
172
|
+
yourAgentId: requestInfo.agentId,
|
|
173
|
+
success: false,
|
|
174
|
+
message:
|
|
175
|
+
"allowedHosts and at least one of headerTemplate or queryTemplate are required for upsert.",
|
|
176
|
+
bindings,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const placeholder = placeholderForConfigKey(args.configKey);
|
|
182
|
+
if (args.headerTemplate && !args.headerTemplate.includes(placeholder)) {
|
|
183
|
+
return {
|
|
184
|
+
content: [{ type: "text", text: `headerTemplate must include ${placeholder}.` }],
|
|
185
|
+
structuredContent: {
|
|
186
|
+
yourAgentId: requestInfo.agentId,
|
|
187
|
+
success: false,
|
|
188
|
+
message: `headerTemplate must include ${placeholder}.`,
|
|
189
|
+
bindings,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (args.queryTemplate && !args.queryTemplate.includes(placeholder)) {
|
|
194
|
+
return {
|
|
195
|
+
content: [{ type: "text", text: `queryTemplate must include ${placeholder}.` }],
|
|
196
|
+
structuredContent: {
|
|
197
|
+
yourAgentId: requestInfo.agentId,
|
|
198
|
+
success: false,
|
|
199
|
+
message: `queryTemplate must include ${placeholder}.`,
|
|
200
|
+
bindings,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const nextBinding = CredentialBindingSchema.parse({
|
|
206
|
+
configKey: args.configKey,
|
|
207
|
+
allowedHosts: args.allowedHosts,
|
|
208
|
+
headerTemplate: args.headerTemplate,
|
|
209
|
+
queryTemplate: args.queryTemplate,
|
|
210
|
+
scope,
|
|
211
|
+
scopeId,
|
|
212
|
+
active: true,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
upsertCredentialBinding({
|
|
216
|
+
id: args.id,
|
|
217
|
+
configKey: nextBinding.configKey,
|
|
218
|
+
allowedHosts: nextBinding.allowedHosts,
|
|
219
|
+
headerTemplate: nextBinding.headerTemplate,
|
|
220
|
+
queryTemplate: nextBinding.queryTemplate,
|
|
221
|
+
scope: nextBinding.scope,
|
|
222
|
+
scopeId: nextBinding.scopeId ?? null,
|
|
223
|
+
active: true,
|
|
224
|
+
});
|
|
225
|
+
const nextBindings = listRelationalCredentialBindings({ includeInactive: true });
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: "text", text: `Credential binding ${args.configKey} saved.` }],
|
|
229
|
+
structuredContent: {
|
|
230
|
+
yourAgentId: requestInfo.agentId,
|
|
231
|
+
success: true,
|
|
232
|
+
message: `Credential binding ${args.configKey} saved.`,
|
|
233
|
+
bindings: nextBindings,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getEmbeddingProvider, getMemoryStore } from "@/be/memory";
|
|
4
|
+
import { storeLinks } from "@/be/memory/link-resolver";
|
|
5
|
+
import { createToolRegistrar } from "@/tools/utils";
|
|
6
|
+
import { AgentMemorySchema, AgentMemoryScopeSchema } from "@/types";
|
|
7
|
+
|
|
8
|
+
export const registerMemoryEditTool = (server: McpServer) => {
|
|
9
|
+
createToolRegistrar(server)(
|
|
10
|
+
"memory-edit",
|
|
11
|
+
{
|
|
12
|
+
title: "Edit a memory",
|
|
13
|
+
description:
|
|
14
|
+
"Edit a single memory in place while preserving its ID, usefulness posterior, and audit history. Two modes: 'replace' overwrites the entire content (requires `content`); 'exact' performs a surgical find-and-replace of `oldString` with `newString` within the existing content (fails if `oldString` is missing or ambiguous). Use 'replace' for full rewrites, 'exact' for targeted edits.",
|
|
15
|
+
annotations: { destructiveHint: true },
|
|
16
|
+
|
|
17
|
+
inputSchema: z.object({
|
|
18
|
+
memoryId: z.uuid().optional().describe("The memory ID to edit."),
|
|
19
|
+
key: z.string().min(1).optional().describe("Structured key alternative to memoryId."),
|
|
20
|
+
scope: AgentMemoryScopeSchema.optional().describe("Required when editing by key."),
|
|
21
|
+
mode: z
|
|
22
|
+
.enum(["replace", "exact"])
|
|
23
|
+
.default("replace")
|
|
24
|
+
.describe(
|
|
25
|
+
"'replace' overwrites the entire memory content; 'exact' finds a unique substring (oldString) and replaces it with newString.",
|
|
26
|
+
),
|
|
27
|
+
content: z
|
|
28
|
+
.string()
|
|
29
|
+
.min(1)
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Full replacement content. Required for 'replace' mode, ignored in 'exact'."),
|
|
32
|
+
oldString: z
|
|
33
|
+
.string()
|
|
34
|
+
.min(1)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe(
|
|
37
|
+
"Substring to find in existing content. Required for 'exact' mode. Must appear exactly once.",
|
|
38
|
+
),
|
|
39
|
+
newString: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe(
|
|
43
|
+
"Replacement for oldString. Required for 'exact' mode. Can be empty to delete.",
|
|
44
|
+
),
|
|
45
|
+
intent: z.string().min(1).describe("Why you are editing this memory."),
|
|
46
|
+
expectedVersion: z.number().int().min(1).optional(),
|
|
47
|
+
}),
|
|
48
|
+
outputSchema: z.object({
|
|
49
|
+
yourAgentId: z.string().uuid().optional(),
|
|
50
|
+
success: z.boolean(),
|
|
51
|
+
message: z.string(),
|
|
52
|
+
memory: AgentMemorySchema.optional(),
|
|
53
|
+
changed: z.boolean().optional(),
|
|
54
|
+
previousVersion: z.number().int().optional(),
|
|
55
|
+
version: z.number().int().optional(),
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
async (
|
|
59
|
+
{ memoryId, key, scope, mode, content, oldString, newString, intent, expectedVersion },
|
|
60
|
+
requestInfo,
|
|
61
|
+
_meta,
|
|
62
|
+
) => {
|
|
63
|
+
if (!requestInfo.agentId) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text: "Agent ID required to edit memories." }],
|
|
66
|
+
structuredContent: {
|
|
67
|
+
yourAgentId: undefined,
|
|
68
|
+
success: false,
|
|
69
|
+
message: "Agent ID required. Are you registered in the swarm?",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!memoryId && !(key && scope)) {
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: "memoryId or key+scope required." }],
|
|
77
|
+
structuredContent: {
|
|
78
|
+
yourAgentId: requestInfo.agentId,
|
|
79
|
+
success: false,
|
|
80
|
+
message: "memoryId or key+scope required.",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const store = getMemoryStore();
|
|
87
|
+
const result = store.edit({
|
|
88
|
+
id: memoryId,
|
|
89
|
+
key,
|
|
90
|
+
scope,
|
|
91
|
+
agentId: requestInfo.agentId,
|
|
92
|
+
mode,
|
|
93
|
+
content,
|
|
94
|
+
oldString,
|
|
95
|
+
newString,
|
|
96
|
+
intent,
|
|
97
|
+
expectedVersion,
|
|
98
|
+
changedByAgentId: requestInfo.agentId,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (result.changed) {
|
|
102
|
+
const provider = getEmbeddingProvider();
|
|
103
|
+
const embedding = await provider.embed(result.memory.content);
|
|
104
|
+
if (embedding) store.updateEmbedding(result.memory.id, embedding, provider.name);
|
|
105
|
+
try {
|
|
106
|
+
storeLinks(result.memory.id, requestInfo.agentId, result.memory.content);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.error(
|
|
109
|
+
`[memory-edit] Link resolution failed for ${result.memory.id}:`,
|
|
110
|
+
(err as Error).message,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: "text",
|
|
119
|
+
text: result.changed
|
|
120
|
+
? `Memory "${result.memory.id}" edited to version ${result.version}.`
|
|
121
|
+
: `Memory "${result.memory.id}" unchanged.`,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
structuredContent: {
|
|
125
|
+
yourAgentId: requestInfo.agentId,
|
|
126
|
+
success: true,
|
|
127
|
+
message: result.changed
|
|
128
|
+
? `Memory edited to version ${result.version}.`
|
|
129
|
+
: "Memory unchanged.",
|
|
130
|
+
memory: result.memory,
|
|
131
|
+
changed: result.changed,
|
|
132
|
+
previousVersion: result.previousVersion,
|
|
133
|
+
version: result.version,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return {
|
|
138
|
+
content: [{ type: "text", text: `Memory edit failed: ${(err as Error).message}` }],
|
|
139
|
+
structuredContent: {
|
|
140
|
+
yourAgentId: requestInfo.agentId,
|
|
141
|
+
success: false,
|
|
142
|
+
message: `Memory edit failed: ${(err as Error).message}`,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
};
|
|
@@ -54,6 +54,7 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
54
54
|
source: AgentMemorySourceSchema,
|
|
55
55
|
scope: AgentMemoryScopeSchema,
|
|
56
56
|
similarity: z.number().optional(),
|
|
57
|
+
retrievalSource: z.enum(["vec", "fts", "hybrid", "fallback"]).optional(),
|
|
57
58
|
createdAt: z.string(),
|
|
58
59
|
rateHint: z.string().optional(),
|
|
59
60
|
}),
|
|
@@ -82,14 +83,15 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
82
83
|
const store = getMemoryStore();
|
|
83
84
|
const queryEmbedding = await provider.embed(query);
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
const candidateLimit = limit * CANDIDATE_SET_MULTIPLIER;
|
|
87
|
+
const candidates = store.search(queryEmbedding ?? new Float32Array(0), requestInfo.agentId, {
|
|
88
|
+
scope: scope as "agent" | "swarm" | "all",
|
|
89
|
+
limit: candidateLimit,
|
|
90
|
+
source,
|
|
91
|
+
isLead,
|
|
92
|
+
queryText: query,
|
|
93
|
+
});
|
|
94
|
+
if (candidates.length > 0) {
|
|
93
95
|
const ranked = rerank(candidates, { limit });
|
|
94
96
|
|
|
95
97
|
// Retrieval bridge — when called inside a task scope, log one
|
|
@@ -101,7 +103,11 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
101
103
|
recordRetrievals(
|
|
102
104
|
requestInfo.sourceTaskId,
|
|
103
105
|
requestInfo.agentId,
|
|
104
|
-
ranked.map((r) => ({
|
|
106
|
+
ranked.map((r) => ({
|
|
107
|
+
memoryId: r.id,
|
|
108
|
+
similarity: r.similarity,
|
|
109
|
+
retrievalSource: r.retrievalSource,
|
|
110
|
+
})),
|
|
105
111
|
requestInfo.sessionId,
|
|
106
112
|
{ intent, contextKey: requestInfo.contextKey, eventType: "search" },
|
|
107
113
|
);
|
|
@@ -118,6 +124,7 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
118
124
|
source: r.source,
|
|
119
125
|
scope: r.scope,
|
|
120
126
|
similarity: r.similarity,
|
|
127
|
+
retrievalSource: r.retrievalSource,
|
|
121
128
|
createdAt: r.createdAt,
|
|
122
129
|
...(inTaskContext && NUDGE_ELIGIBLE_SOURCES.has(r.source as AgentMemorySource)
|
|
123
130
|
? { rateHint: rateHintFor(r.id) }
|
|
@@ -145,7 +152,7 @@ export const registerMemorySearchTool = (server: McpServer) => {
|
|
|
145
152
|
};
|
|
146
153
|
}
|
|
147
154
|
|
|
148
|
-
// Fallback: list recent memories (no OPENAI_API_KEY)
|
|
155
|
+
// Fallback: list recent memories (no OPENAI_API_KEY and no FTS hit)
|
|
149
156
|
const recent = store.list(requestInfo.agentId, {
|
|
150
157
|
scope: scope as "agent" | "swarm" | "all",
|
|
151
158
|
limit,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getScheduledTaskById,
|
|
7
7
|
getScheduledTaskByName,
|
|
8
8
|
} from "@/be/db";
|
|
9
|
+
import { createEvent } from "@/be/events";
|
|
9
10
|
import { createToolRegistrar } from "@/tools/utils";
|
|
10
11
|
|
|
11
12
|
export const registerDeleteScheduleTool = (server: McpServer) => {
|
|
@@ -14,7 +15,7 @@ export const registerDeleteScheduleTool = (server: McpServer) => {
|
|
|
14
15
|
{
|
|
15
16
|
title: "Delete Scheduled Task",
|
|
16
17
|
description:
|
|
17
|
-
"Delete a scheduled task permanently.
|
|
18
|
+
"Delete a scheduled task permanently. Any registered agent can delete schedules.",
|
|
18
19
|
annotations: { destructiveHint: true },
|
|
19
20
|
|
|
20
21
|
inputSchema: z.object({
|
|
@@ -71,17 +72,13 @@ export const registerDeleteScheduleTool = (server: McpServer) => {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
// Check authorization (creator or lead)
|
|
75
75
|
const caller = getAgentById(requestInfo.agentId);
|
|
76
|
-
|
|
77
|
-
const isLead = caller?.isLead === true;
|
|
78
|
-
|
|
79
|
-
if (!isCreator && !isLead) {
|
|
76
|
+
if (!caller) {
|
|
80
77
|
return {
|
|
81
|
-
content: [{ type: "text", text: "
|
|
78
|
+
content: [{ type: "text", text: "Agent not found." }],
|
|
82
79
|
structuredContent: {
|
|
83
80
|
success: false,
|
|
84
|
-
message: "
|
|
81
|
+
message: "Agent not found.",
|
|
85
82
|
},
|
|
86
83
|
};
|
|
87
84
|
}
|
|
@@ -99,6 +96,19 @@ export const registerDeleteScheduleTool = (server: McpServer) => {
|
|
|
99
96
|
};
|
|
100
97
|
}
|
|
101
98
|
|
|
99
|
+
createEvent({
|
|
100
|
+
category: "system",
|
|
101
|
+
event: "schedule.deleted",
|
|
102
|
+
source: "api",
|
|
103
|
+
agentId: requestInfo.agentId,
|
|
104
|
+
data: {
|
|
105
|
+
scheduleId: schedule.id,
|
|
106
|
+
name: schedule.name,
|
|
107
|
+
deletedByAgentId: requestInfo.agentId,
|
|
108
|
+
createdByAgentId: schedule.createdByAgentId,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
102
112
|
return {
|
|
103
113
|
content: [{ type: "text", text: `Deleted schedule "${schedule.name}".` }],
|
|
104
114
|
structuredContent: {
|
|
@@ -51,8 +51,7 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
51
51
|
{
|
|
52
52
|
title: "Update Scheduled Task",
|
|
53
53
|
annotations: { idempotentHint: true },
|
|
54
|
-
description:
|
|
55
|
-
"Update an existing scheduled task. Only the creator or lead agent can update schedules.",
|
|
54
|
+
description: "Update an existing scheduled task. Any registered agent can update schedules.",
|
|
56
55
|
inputSchema: updateScheduleInputSchema,
|
|
57
56
|
outputSchema: z.object({
|
|
58
57
|
yourAgentId: z.string().uuid().optional(),
|
|
@@ -132,17 +131,13 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
132
131
|
};
|
|
133
132
|
}
|
|
134
133
|
|
|
135
|
-
// Check authorization (creator or lead)
|
|
136
134
|
const caller = getAgentById(requestInfo.agentId);
|
|
137
|
-
|
|
138
|
-
const isLead = caller?.isLead === true;
|
|
139
|
-
|
|
140
|
-
if (!isCreator && !isLead) {
|
|
135
|
+
if (!caller) {
|
|
141
136
|
return {
|
|
142
|
-
content: [{ type: "text", text: "
|
|
137
|
+
content: [{ type: "text", text: "Agent not found." }],
|
|
143
138
|
structuredContent: {
|
|
144
139
|
success: false,
|
|
145
|
-
message: "
|
|
140
|
+
message: "Agent not found.",
|
|
146
141
|
},
|
|
147
142
|
};
|
|
148
143
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registerScriptConnectionsTool } from "./tool";
|