@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.
Files changed (122) hide show
  1. package/README.md +2 -0
  2. package/dist/{actions-7txktrdj.js → actions-2expzt47.js} +6 -6
  3. package/dist/{app-xm3xsdye.js → app-dr8hwx7z.js} +3 -3
  4. package/dist/{assistant-qpv63wk6.js → assistant-9rhgsw7v.js} +9 -10
  5. package/dist/{boot-reembed-chxhrwv8.js → boot-reembed-3q1aywnz.js} +5 -4
  6. package/dist/{boot-reembed-9cxqka3e.js → boot-reembed-9kt97g1z.js} +4 -3
  7. package/dist/{boot-scrub-logs-8qtfkcz8.js → boot-scrub-logs-vskq108e.js} +2 -2
  8. package/dist/{cli-fedn86nz.js → cli-0jw6j755.js} +8 -3
  9. package/dist/{cli-yeemwevj.js → cli-23zk7xqy.js} +20 -16
  10. package/dist/{cli-v9283nma.js → cli-2g9jf9ek.js} +1 -1
  11. package/dist/{cli-rvae030h.js → cli-2hap19dv.js} +3 -3
  12. package/dist/{cli-wjyyv518.js → cli-3j01d33e.js} +9 -14
  13. package/dist/{cli-8hyv6c2v.js → cli-54h5daha.js} +41 -23
  14. package/dist/{cli-fygaw191.js → cli-5pf0b84v.js} +2 -2
  15. package/dist/{cli-m8f6qzck.js → cli-7v4y3hyd.js} +1 -1
  16. package/dist/{cli-fwxdt7kt.js → cli-d4z1csms.js} +30 -5
  17. package/dist/{cli-jt9d9fjw.js → cli-e7bwjntj.js} +1 -1
  18. package/dist/{cli-s14sb64w.js → cli-etvgz5x8.js} +5 -7
  19. package/dist/{cli-2qynerth.js → cli-gj2n2ec1.js} +1 -1
  20. package/dist/{cli-dz3d6zjg.js → cli-nzc0h54v.js} +121 -2
  21. package/dist/{cli-8w95v19d.js → cli-p4cj4vhc.js} +351 -24
  22. package/dist/{cli-xmtsan9k.js → cli-q5tshxd6.js} +1 -1
  23. package/dist/{http-zts4haq7.js → cli-qvzgncd8.js} +83966 -76422
  24. package/dist/{cli-4fnp2tc3.js → cli-s42f54ja.js} +1 -1
  25. package/dist/{cli-krvxq8bc.js → cli-t9v14cnd.js} +23 -4
  26. package/dist/{cli-gzepjz54.js → cli-v1syqkcb.js} +900 -352
  27. package/dist/{cli-ksq38x4n.js → cli-w1nfskkg.js} +2 -2
  28. package/dist/{cli-ns0r7mkr.js → cli-y9p3e94h.js} +3 -3
  29. package/dist/{cli-85pf4z38.js → cli-yjt8a36k.js} +3 -3
  30. package/dist/{cli-yfwwjeft.js → cli-yvektv79.js} +1 -1
  31. package/dist/{cli-kk51f3tf.js → cli-zaxksbgj.js} +5 -5
  32. package/dist/{cli-rttgde5f.js → cli-zghef0em.js} +1 -1
  33. package/dist/cli.js +10 -10
  34. package/dist/{commands-aqn63mcw.js → commands-wfrkef57.js} +2 -2
  35. package/dist/{db-azrvwsnj.js → db-c42pxt7h.js} +2 -2
  36. package/dist/{handlers-hf61har3.js → handlers-n36zkfvx.js} +10 -12
  37. package/dist/{hook-306p3yz4.js → hook-gw3vhv6s.js} +7 -5
  38. package/dist/http-59ygpn2h.js +17263 -0
  39. package/dist/{index-h2yqjyk0.js → index-881c1baf.js} +9 -8
  40. package/dist/{index-29vg51x6.js → index-jca7jdpt.js} +23 -10
  41. package/dist/{index-bfh9hgek.js → index-xf6fp4y1.js} +5 -5
  42. package/dist/{index-3c651yfk.js → index-xz8vaa5c.js} +14 -11
  43. package/dist/{keepalive-a0dg5pds.js → keepalive-mj4302vw.js} +4 -4
  44. package/dist/{lead-7mcxedkc.js → lead-qm0xjvkv.js} +19 -19
  45. package/dist/{maintenance-mrzqd53t.js → maintenance-xppxbe4t.js} +5 -4
  46. package/dist/{onboard-4dkpv9wa.js → onboard-ejx6yxh8.js} +2 -2
  47. package/dist/{otel-impl-jt7gpyp9.js → otel-impl-zs5exkpk.js} +1 -1
  48. package/dist/{pricing-refresh-xqnzh8dt.js → pricing-refresh-nqyf8bkb.js} +4 -4
  49. package/dist/{seed-pricing-56tjm1fj.js → seed-pricing-w3x550cj.js} +3 -3
  50. package/dist/{setup-tbwk8j10.js → setup-7729ktfj.js} +2 -2
  51. package/dist/{worker-e03za92t.js → worker-4ttemwhw.js} +19 -19
  52. package/openapi.json +90 -4
  53. package/package.json +3 -3
  54. package/src/be/memory/constants.ts +6 -0
  55. package/src/be/memory/providers/sqlite-store.ts +468 -71
  56. package/src/be/memory/raters/retrieval.ts +4 -2
  57. package/src/be/memory/reranker.ts +5 -2
  58. package/src/be/memory/retrieval-store.ts +2 -0
  59. package/src/be/memory/types.ts +46 -0
  60. package/src/be/migrations/099_memory_structured_key_versioning.sql +41 -0
  61. package/src/be/migrations/100_memory_retrieval_source.sql +8 -0
  62. package/src/be/migrations/101_script_connections.sql +67 -0
  63. package/src/be/script-connections.ts +744 -0
  64. package/src/be/script-credential-broker.ts +38 -0
  65. package/src/be/scripts/typecheck.ts +23 -2
  66. package/src/be/seed-scripts/catalog/boot-triage.inline.ts +16 -4
  67. package/src/be/seed-scripts/catalog/boot-triage.ts +16 -4
  68. package/src/commands/runner.ts +8 -6
  69. package/src/heartbeat/heartbeat.ts +42 -1
  70. package/src/heartbeat/index.ts +7 -1
  71. package/src/http/memory.ts +127 -14
  72. package/src/http/scripts.ts +15 -14
  73. package/src/scripts-runtime/api-client.ts +100 -0
  74. package/src/scripts-runtime/api-types.ts +45 -0
  75. package/src/scripts-runtime/credential-broker/README.md +40 -0
  76. package/src/scripts-runtime/credential-broker/broker.ts +51 -0
  77. package/src/scripts-runtime/credential-broker/default-bindings.ts +19 -0
  78. package/src/scripts-runtime/credential-broker/fetch-patch.ts +102 -0
  79. package/src/scripts-runtime/credential-broker/index.ts +17 -0
  80. package/src/scripts-runtime/credential-broker/store.ts +72 -0
  81. package/src/scripts-runtime/credential-broker/types.ts +54 -0
  82. package/src/scripts-runtime/ctx.ts +11 -1
  83. package/src/scripts-runtime/egress-secrets.ts +14 -76
  84. package/src/scripts-runtime/eval-harness.ts +1 -1
  85. package/src/scripts-runtime/executors/types.ts +5 -5
  86. package/src/scripts-runtime/loader.ts +6 -1
  87. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  88. package/src/scripts-runtime/types/stdlib.d.ts +11 -0
  89. package/src/scripts-runtime/types/swarm-sdk.d.ts +11 -0
  90. package/src/server.ts +6 -0
  91. package/src/tests/credential-broker.test.ts +281 -0
  92. package/src/tests/heartbeat.test.ts +239 -0
  93. package/src/tests/memory-edit.test.ts +177 -0
  94. package/src/tests/memory-hybrid.test.ts +212 -0
  95. package/src/tests/runner-repo-autostash.test.ts +39 -8
  96. package/src/tests/script-connections.test.ts +360 -0
  97. package/src/tests/scripts-http.test.ts +16 -10
  98. package/src/tests/scripts-runtime-secret-egress.test.ts +26 -5
  99. package/src/tests/swarm-config-reserved-keys.test.ts +23 -0
  100. package/src/tests/update-schedule-mcp-tool.test.ts +83 -4
  101. package/src/tools/credential-bindings/index.ts +1 -0
  102. package/src/tools/credential-bindings/tool.ts +238 -0
  103. package/src/tools/memory-edit.ts +148 -0
  104. package/src/tools/memory-search.ts +17 -10
  105. package/src/tools/schedules/delete-schedule.ts +18 -8
  106. package/src/tools/schedules/update-schedule.ts +4 -9
  107. package/src/tools/script-connections/index.ts +1 -0
  108. package/src/tools/script-connections/tool.ts +167 -0
  109. package/src/tools/swarm-config/delete-config.ts +5 -0
  110. package/src/tools/swarm-config/set-config.ts +23 -1
  111. package/src/tools/tool-config.ts +6 -1
  112. package/src/types.ts +6 -0
  113. package/src/workflows/executors/swarm-script.ts +2 -0
  114. package/templates/community/dora-metrics/PLAYBOOK.md +294 -0
  115. package/templates/community/dora-metrics/README.md +39 -0
  116. package/templates/community/dora-metrics/lead-prompt.md +56 -0
  117. package/templates/community/dora-metrics/report.mjs +393 -0
  118. package/templates/community/dora-metrics/run.sh +113 -0
  119. package/templates/schedules/weekly-dora-metrics/config.json +13 -0
  120. package/templates/schedules/weekly-dora-metrics/content.md +61 -0
  121. package/dist/cli-2307phk1.js +0 -24223
  122. 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
- if (queryEmbedding) {
86
- const candidateLimit = limit * CANDIDATE_SET_MULTIPLIER;
87
- const candidates = store.search(queryEmbedding, requestInfo.agentId, {
88
- scope: scope as "agent" | "swarm" | "all",
89
- limit: candidateLimit,
90
- source,
91
- isLead,
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) => ({ memoryId: r.id, similarity: r.similarity })),
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. Only the creator or lead agent can delete schedules.",
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
- const isCreator = schedule.createdByAgentId === requestInfo.agentId;
77
- const isLead = caller?.isLead === true;
78
-
79
- if (!isCreator && !isLead) {
76
+ if (!caller) {
80
77
  return {
81
- content: [{ type: "text", text: "Only the creator or lead can delete this schedule." }],
78
+ content: [{ type: "text", text: "Agent not found." }],
82
79
  structuredContent: {
83
80
  success: false,
84
- message: "Only the creator or lead can delete this schedule.",
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
- const isCreator = schedule.createdByAgentId === requestInfo.agentId;
138
- const isLead = caller?.isLead === true;
139
-
140
- if (!isCreator && !isLead) {
135
+ if (!caller) {
141
136
  return {
142
- content: [{ type: "text", text: "Only the creator or lead can update this schedule." }],
137
+ content: [{ type: "text", text: "Agent not found." }],
143
138
  structuredContent: {
144
139
  success: false,
145
- message: "Only the creator or lead can update this schedule.",
140
+ message: "Agent not found.",
146
141
  },
147
142
  };
148
143
  }
@@ -0,0 +1 @@
1
+ export { registerScriptConnectionsTool } from "./tool";