@desplega.ai/agent-swarm 1.123.0 → 1.124.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 (234) hide show
  1. package/README.md +2 -1
  2. package/dist/{actions-e4c9f0xy.js → actions-z3d0fk7z.js} +6 -6
  3. package/dist/{app-vmvmj2v3.js → app-q2rc9tdr.js} +4 -4
  4. package/dist/{assistant-yn7a792a.js → assistant-3stjq7fz.js} +9 -9
  5. package/dist/{boot-reembed-xg1r86h2.js → boot-reembed-5867whnb.js} +3 -3
  6. package/dist/{boot-reembed-chxty50a.js → boot-reembed-v6r1df32.js} +4 -4
  7. package/dist/{boot-scrub-logs-exwddvp5.js → boot-scrub-logs-8b8jegk3.js} +2 -2
  8. package/dist/{cli-1592nfd6.js → cli-0925phzv.js} +1 -1
  9. package/dist/{cli-hbbxmhec.js → cli-2yr6edr7.js} +4 -4
  10. package/dist/{cli-8cq4z4x7.js → cli-3z4q09tn.js} +182 -19
  11. package/dist/{cli-vz9drmce.js → cli-5jn6wnd9.js} +17 -8
  12. package/dist/{cli-5arfywtm.js → cli-5ncdb7ff.js} +19 -9
  13. package/dist/{cli-3tv9z4wx.js → cli-92bqgbgy.js} +1 -1
  14. package/dist/{cli-fjf04hpa.js → cli-dq2ssyf0.js} +48 -56
  15. package/dist/{cli-mngsj9fx.js → cli-gkvf8d83.js} +1 -1
  16. package/dist/{cli-mepk1j0t.js → cli-gzjsamwc.js} +2 -2
  17. package/dist/{cli-c9m59f83.js → cli-h89g0qrd.js} +1 -1
  18. package/dist/{cli-n8mf7x4b.js → cli-jp4mdj9d.js} +2 -2
  19. package/dist/{cli-822d4bjk.js → cli-kk58tg33.js} +7 -7
  20. package/dist/{cli-9hj1adgp.js → cli-mcez7z4p.js} +1 -1
  21. package/dist/{cli-byv3720g.js → cli-mmk5vagg.js} +2 -2
  22. package/dist/{cli-zdp11t8m.js → cli-p0ec4vv6.js} +1 -1
  23. package/dist/{cli-h2say6xk.js → cli-p0zgv8pj.js} +3 -1
  24. package/dist/{cli-8ef5ky75.js → cli-perb20ma.js} +1 -1
  25. package/dist/{cli-zkj6f2sk.js → cli-qf7acvyr.js} +90 -4
  26. package/dist/{cli-kmm1rwmp.js → cli-qwsagsmg.js} +1 -1
  27. package/dist/{cli-we91ywvy.js → cli-sqv6c9b8.js} +6 -6
  28. package/dist/{cli-np0yhmmk.js → cli-vm20sh8d.js} +3 -3
  29. package/dist/{cli-p11rf59d.js → cli-wn3m6q54.js} +3 -3
  30. package/dist/{cli-mkpf4ndf.js → cli-x268say8.js} +2976 -5621
  31. package/dist/{cli-ngbsk4yx.js → cli-y43n987v.js} +1 -1
  32. package/dist/{cli-4509mwm5.js → cli-ykthjw29.js} +8 -8
  33. package/dist/{cli-9eka6jwv.js → cli-zxb72ctk.js} +2 -2
  34. package/dist/cli.js +12 -10
  35. package/dist/{commands-sjk3zfyr.js → commands-sda76yn8.js} +2 -2
  36. package/dist/{db-2je5agjb.js → db-vn9e4rqj.js} +6 -2
  37. package/dist/{e2b-2s4psnbf.js → e2b-q345y8s4.js} +0 -4
  38. package/dist/{handlers-yzv369hf.js → handlers-xfja18ac.js} +9 -9
  39. package/dist/{hook-rfsj2r8x.js → hook-2medrp47.js} +1 -40
  40. package/dist/{http-v9rr144m.js → http-937pyjfc.js} +99 -44
  41. package/dist/{index-nr2199m6.js → index-2bqd2q9v.js} +11 -11
  42. package/dist/{index-3xtk777g.js → index-gw4en7jg.js} +9 -9
  43. package/dist/{index-c3tan44f.js → index-knqczmnm.js} +10 -10
  44. package/dist/{index-smjdc3h9.js → index-vah60vxp.js} +8 -8
  45. package/dist/{keepalive-5ds53bjd.js → keepalive-20rd6hxh.js} +5 -5
  46. package/dist/{lead-5xhez25b.js → lead-7w2k3a49.js} +21 -21
  47. package/dist/{maintenance-b43d24q6.js → maintenance-p3x918yw.js} +4 -4
  48. package/dist/{oauth-refresh-sweep-qe286vn2.js → oauth-refresh-sweep-shm0nzm4.js} +4 -4
  49. package/dist/{onboard-c4r3ds3z.js → onboard-py9dnf54.js} +6 -2
  50. package/dist/{otel-impl-nv3rjw61.js → otel-impl-7yjkfg68.js} +1 -1
  51. package/dist/{pi-mono-adapter-2syx1x4d.js → pi-mono-adapter-z6h98fva.js} +4 -38
  52. package/dist/{pricing-refresh-5ct2wp4k.js → pricing-refresh-3snb6370.js} +4 -4
  53. package/dist/{rbac-roles-m502w0qv.js → rbac-roles-5e72bbpk.js} +3 -3
  54. package/dist/{rbac-roles-b82cxpxn.js → rbac-roles-gqxdp8st.js} +4 -4
  55. package/dist/{seed-pricing-jhjphbf0.js → seed-pricing-bg42d7h2.js} +3 -3
  56. package/dist/{setup-zbaspydq.js → setup-nzk3kbbq.js} +2 -2
  57. package/dist/{worker-snvhpax5.js → worker-0p1jdzkm.js} +21 -21
  58. package/openapi.json +146 -1
  59. package/package.json +3 -1
  60. package/src/be/db.ts +81 -4
  61. package/src/be/models-catalog.ts +156 -0
  62. package/src/be/modelsdev-cache.ts +14 -1
  63. package/src/be/pricing-refresh.ts +2 -0
  64. package/src/be/scripts/typecheck.ts +17 -4
  65. package/src/be/seed-scripts/catalog/task-context-gathering.ts +1 -1
  66. package/src/commands/onboard/env-generator.ts +12 -0
  67. package/src/e2b/env.ts +0 -4
  68. package/src/hooks/hook.ts +0 -67
  69. package/src/http/all-routes.ts +1 -0
  70. package/src/http/index.ts +2 -0
  71. package/src/http/models-catalog.ts +65 -0
  72. package/src/http/workflows.ts +16 -4
  73. package/src/prompts/base-prompt.ts +8 -7
  74. package/src/prompts/session-templates.ts +106 -12
  75. package/src/providers/pi-mono-adapter.ts +12 -2
  76. package/src/providers/pi-mono-extension.ts +0 -64
  77. package/src/providers/pricing-sources.md +16 -1
  78. package/src/scripts-runtime/eval-harness.ts +18 -1
  79. package/src/scripts-runtime/swarm-sdk.ts +10 -0
  80. package/src/scripts-runtime/types/stdlib.d.ts +13 -0
  81. package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -0
  82. package/src/server-user.ts +4 -7
  83. package/src/slack/blocks.ts +21 -8
  84. package/src/slack/responses.ts +27 -51
  85. package/src/slack/watcher.ts +22 -5
  86. package/src/telemetry.ts +169 -3
  87. package/src/tests/base-prompt.test.ts +79 -0
  88. package/src/tests/mcp-tools-user.test.ts +62 -16
  89. package/src/tests/mcp-tools.test.ts +6 -3
  90. package/src/tests/memory-edit.test.ts +21 -4
  91. package/src/tests/model-groups-live-catalog.test.ts +65 -0
  92. package/src/tests/models-catalog.test.ts +119 -0
  93. package/src/tests/oauth-access-token-tool.test.ts +71 -1
  94. package/src/tests/pricing-refresh.test.ts +25 -0
  95. package/src/tests/prompt-template-session.test.ts +142 -5
  96. package/src/tests/rbac-charact-skills.test.ts +81 -14
  97. package/src/tests/script-apis-mcp.test.ts +56 -8
  98. package/src/tests/scripts-mcp-e2e.test.ts +157 -8
  99. package/src/tests/scripts-typecheck.test.ts +17 -0
  100. package/src/tests/sdk-allowlist.test.ts +34 -1
  101. package/src/tests/seed-scripts.test.ts +43 -0
  102. package/src/tests/slack-blocks.test.ts +2 -1
  103. package/src/tests/slack-inline-output.test.ts +24 -30
  104. package/src/tests/slack-watcher.test.ts +42 -0
  105. package/src/tests/steer-task-tool.test.ts +37 -8
  106. package/src/tests/steering-transport.test.ts +18 -3
  107. package/src/tests/swarm-tool-result-gate.test.ts +399 -0
  108. package/src/tests/task-tools-ctx.test.ts +49 -17
  109. package/src/tests/task-tools-ownership.test.ts +41 -13
  110. package/src/tests/telemetry-init.test.ts +376 -2
  111. package/src/tests/tool-output-agent-id.test.ts +14 -2
  112. package/src/tests/workflow-http-v2.test.ts +116 -0
  113. package/src/tools/accept-steer.ts +45 -53
  114. package/src/tools/cancel-task.ts +31 -41
  115. package/src/tools/context-diff.ts +19 -63
  116. package/src/tools/context-history.ts +22 -51
  117. package/src/tools/create-channel.ts +24 -39
  118. package/src/tools/create-metric.ts +19 -82
  119. package/src/tools/create-page.ts +20 -81
  120. package/src/tools/credential-bindings/tool.ts +125 -246
  121. package/src/tools/db-query.ts +13 -24
  122. package/src/tools/delete-channel.ts +25 -71
  123. package/src/tools/delete-page.ts +27 -75
  124. package/src/tools/get-metrics.ts +29 -22
  125. package/src/tools/get-swarm.ts +44 -15
  126. package/src/tools/get-task-details.ts +150 -32
  127. package/src/tools/get-tasks.ts +63 -29
  128. package/src/tools/inject-learning.ts +8 -38
  129. package/src/tools/join-swarm.ts +45 -47
  130. package/src/tools/kv/kv-delete.ts +13 -37
  131. package/src/tools/kv/kv-get.ts +38 -29
  132. package/src/tools/kv/kv-incr.ts +28 -56
  133. package/src/tools/kv/kv-list.ts +40 -31
  134. package/src/tools/kv/kv-set.ts +34 -76
  135. package/src/tools/list-channels.ts +24 -17
  136. package/src/tools/list-services.ts +37 -45
  137. package/src/tools/manage-user.ts +53 -66
  138. package/src/tools/mcp-servers/mcp-server-create.ts +19 -55
  139. package/src/tools/mcp-servers/mcp-server-delete.ts +9 -39
  140. package/src/tools/mcp-servers/mcp-server-get.ts +9 -35
  141. package/src/tools/mcp-servers/mcp-server-install.ts +13 -60
  142. package/src/tools/mcp-servers/mcp-server-list.ts +28 -26
  143. package/src/tools/mcp-servers/mcp-server-uninstall.ts +10 -36
  144. package/src/tools/mcp-servers/mcp-server-update.ts +13 -57
  145. package/src/tools/memory-delete.ts +16 -46
  146. package/src/tools/memory-edit.ts +48 -49
  147. package/src/tools/memory-get.ts +40 -36
  148. package/src/tools/memory-rate.ts +14 -44
  149. package/src/tools/memory-search.ts +46 -52
  150. package/src/tools/my-agent-info.ts +39 -33
  151. package/src/tools/oauth-access-token.ts +9 -24
  152. package/src/tools/poll-task.ts +50 -77
  153. package/src/tools/post-message.ts +24 -38
  154. package/src/tools/prompt-templates/delete.ts +16 -48
  155. package/src/tools/prompt-templates/get.ts +45 -42
  156. package/src/tools/prompt-templates/list.ts +29 -44
  157. package/src/tools/prompt-templates/preview.ts +14 -40
  158. package/src/tools/prompt-templates/set.ts +30 -52
  159. package/src/tools/read-messages.ts +45 -54
  160. package/src/tools/register-agentmail-inbox.ts +28 -84
  161. package/src/tools/register-kapso-number.ts +20 -50
  162. package/src/tools/register-service.ts +36 -44
  163. package/src/tools/repos/get-repos.ts +29 -21
  164. package/src/tools/repos/update-repo.ts +30 -27
  165. package/src/tools/request-human-input.ts +10 -33
  166. package/src/tools/resolve-user.ts +59 -16
  167. package/src/tools/schedules/create-schedule.ts +58 -173
  168. package/src/tools/schedules/delete-schedule.ts +16 -56
  169. package/src/tools/schedules/list-schedules.ts +41 -67
  170. package/src/tools/schedules/patch-schedule.ts +57 -153
  171. package/src/tools/schedules/run-schedule-now.ts +18 -59
  172. package/src/tools/schedules/update-schedule.ts +57 -153
  173. package/src/tools/script-apis.ts +46 -28
  174. package/src/tools/script-common.ts +129 -34
  175. package/src/tools/script-connections/tool.ts +59 -154
  176. package/src/tools/script-query-types.ts +43 -3
  177. package/src/tools/script-run.ts +41 -2
  178. package/src/tools/script-runs.ts +69 -1
  179. package/src/tools/script-search.ts +24 -1
  180. package/src/tools/script-upsert.ts +18 -3
  181. package/src/tools/send-task.ts +32 -81
  182. package/src/tools/skills/skill-create.ts +14 -39
  183. package/src/tools/skills/skill-delete.ts +14 -42
  184. package/src/tools/skills/skill-get-file.ts +10 -43
  185. package/src/tools/skills/skill-get.ts +9 -32
  186. package/src/tools/skills/skill-install-remote.ts +16 -52
  187. package/src/tools/skills/skill-install.ts +14 -52
  188. package/src/tools/skills/skill-list.ts +24 -26
  189. package/src/tools/skills/skill-publish.ts +18 -54
  190. package/src/tools/skills/skill-search.ts +21 -18
  191. package/src/tools/skills/skill-sync-remote.ts +12 -24
  192. package/src/tools/skills/skill-uninstall.ts +10 -26
  193. package/src/tools/skills/skill-update.ts +24 -81
  194. package/src/tools/slack-delete.ts +8 -32
  195. package/src/tools/slack-download-file.ts +17 -57
  196. package/src/tools/slack-list-channels.ts +16 -43
  197. package/src/tools/slack-post.ts +11 -40
  198. package/src/tools/slack-read.ts +33 -103
  199. package/src/tools/slack-reply.ts +16 -53
  200. package/src/tools/slack-start-thread.ts +14 -55
  201. package/src/tools/slack-update.ts +8 -35
  202. package/src/tools/slack-upload-file.ts +22 -122
  203. package/src/tools/steer-task.ts +22 -35
  204. package/src/tools/store-progress.ts +11 -26
  205. package/src/tools/swarm-config/delete-config.ts +19 -57
  206. package/src/tools/swarm-config/get-config.ts +36 -44
  207. package/src/tools/swarm-config/list-config.ts +36 -44
  208. package/src/tools/swarm-config/set-config.ts +35 -73
  209. package/src/tools/swarm-x.ts +20 -26
  210. package/src/tools/task-action.ts +26 -46
  211. package/src/tools/task-tool-ctx.ts +5 -13
  212. package/src/tools/tracker/tracker-link-task.ts +8 -22
  213. package/src/tools/tracker/tracker-map-agent.ts +8 -22
  214. package/src/tools/tracker/tracker-status.ts +27 -19
  215. package/src/tools/tracker/tracker-sync-status.ts +8 -18
  216. package/src/tools/tracker/tracker-unlink.ts +4 -16
  217. package/src/tools/unregister-service.ts +19 -59
  218. package/src/tools/update-profile.ts +60 -100
  219. package/src/tools/update-service-status.ts +42 -67
  220. package/src/tools/utils.ts +189 -8
  221. package/src/tools/whatsapp-message.ts +19 -32
  222. package/src/tools/workflows/cancel-workflow-run.ts +4 -16
  223. package/src/tools/workflows/create-workflow.ts +9 -38
  224. package/src/tools/workflows/delete-workflow.ts +5 -17
  225. package/src/tools/workflows/get-workflow-run.ts +41 -31
  226. package/src/tools/workflows/get-workflow.ts +10 -21
  227. package/src/tools/workflows/list-workflow-runs.ts +107 -34
  228. package/src/tools/workflows/list-workflows.ts +5 -17
  229. package/src/tools/workflows/patch-workflow-node.ts +11 -39
  230. package/src/tools/workflows/patch-workflow.ts +11 -36
  231. package/src/tools/workflows/retry-workflow-run.ts +4 -16
  232. package/src/tools/workflows/trigger-workflow.ts +22 -58
  233. package/src/tools/workflows/update-workflow.ts +10 -42
  234. package/templates/skills/swarm-scripts/SKILL.md +1 -1
@@ -3,7 +3,7 @@ import * as z from "zod";
3
3
  import { getAgentById } from "@/be/db";
4
4
  import { getMemoryStore } from "@/be/memory";
5
5
  import { can } from "@/rbac";
6
- import { createToolRegistrar } from "@/tools/utils";
6
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
7
7
 
8
8
  export const registerMemoryDeleteTool = (server: McpServer) => {
9
9
  createToolRegistrar(server)(
@@ -17,36 +17,22 @@ export const registerMemoryDeleteTool = (server: McpServer) => {
17
17
  inputSchema: z.object({
18
18
  memoryId: z.uuid().describe("The ID of the memory to delete."),
19
19
  }),
20
- outputSchema: z.object({
20
+ outputSchema: swarmToolOutputSchema({
21
21
  yourAgentId: z.string().optional(),
22
- success: z.boolean(),
23
- message: z.string(),
24
22
  }),
25
23
  },
26
24
  async ({ memoryId }, requestInfo, _meta) => {
27
25
  if (!requestInfo.agentId) {
28
- return {
29
- content: [{ type: "text", text: "Agent ID required to delete memories." }],
30
- structuredContent: {
31
- yourAgentId: undefined,
32
- success: false,
33
- message: "Agent ID required. Are you registered in the swarm?",
34
- },
35
- };
26
+ return toolErr("Agent ID required. Are you registered in the swarm?");
36
27
  }
37
28
 
38
29
  const store = getMemoryStore();
39
30
  const memory = store.peek(memoryId);
40
31
 
41
32
  if (!memory) {
42
- return {
43
- content: [{ type: "text", text: `Memory "${memoryId}" not found.` }],
44
- structuredContent: {
45
- yourAgentId: requestInfo.agentId,
46
- success: false,
47
- message: `Memory "${memoryId}" not found.`,
48
- },
49
- };
33
+ return toolErr(`Memory "${memoryId}" not found.`, {
34
+ data: { yourAgentId: requestInfo.agentId },
35
+ });
50
36
  }
51
37
 
52
38
  // Permission check: own memories or lead can delete swarm-scoped
@@ -62,36 +48,20 @@ export const registerMemoryDeleteTool = (server: McpServer) => {
62
48
  source: "mcp",
63
49
  });
64
50
  if (!decision.allow) {
65
- return {
66
- content: [{ type: "text", text: "You don't have permission to delete this memory." }],
67
- structuredContent: {
68
- yourAgentId: requestInfo.agentId,
69
- success: false,
70
- message:
71
- "Permission denied. You can only delete your own memories, or swarm memories if you are the lead.",
72
- },
73
- };
51
+ return toolErr(
52
+ "Permission denied. You can only delete your own memories, or swarm memories if you are the lead.",
53
+ { data: { yourAgentId: requestInfo.agentId } },
54
+ );
74
55
  }
75
56
 
76
57
  const deleted = store.delete(memoryId);
77
58
 
78
- return {
79
- content: [
80
- {
81
- type: "text",
82
- text: deleted
83
- ? `Memory "${memoryId}" deleted.`
84
- : `Failed to delete memory "${memoryId}".`,
85
- },
86
- ],
87
- structuredContent: {
88
- yourAgentId: requestInfo.agentId,
89
- success: deleted,
90
- message: deleted
91
- ? `Memory "${memoryId}" deleted.`
92
- : `Failed to delete memory "${memoryId}".`,
93
- },
94
- };
59
+ const message = deleted
60
+ ? `Memory "${memoryId}" deleted.`
61
+ : `Failed to delete memory "${memoryId}".`;
62
+ return deleted
63
+ ? toolOk(message, { data: { yourAgentId: requestInfo.agentId } })
64
+ : toolErr(message, { data: { yourAgentId: requestInfo.agentId } });
95
65
  },
96
66
  );
97
67
  };
@@ -2,8 +2,33 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import * as z from "zod";
3
3
  import { getEmbeddingProvider, getMemoryStore } from "@/be/memory";
4
4
  import { refreshLinks } from "@/be/memory/link-resolver";
5
- import { createToolRegistrar } from "@/tools/utils";
6
- import { AgentMemorySchema, AgentMemoryScopeSchema } from "@/types";
5
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
6
+ import { AgentMemoryScopeSchema, AgentMemorySourceSchema } from "@/types";
7
+
8
+ // Loose, format-pin-free mirror of AgentMemorySchema for MCP output validation.
9
+ const agentMemoryOutputSchema = z.looseObject({
10
+ id: z.string().optional(),
11
+ agentId: z.string().nullable().optional(),
12
+ scope: AgentMemoryScopeSchema.optional(),
13
+ key: z.string().nullable().optional(),
14
+ name: z.string().optional(),
15
+ content: z.string().optional(),
16
+ summary: z.string().nullable().optional(),
17
+ source: AgentMemorySourceSchema.optional(),
18
+ sourceTaskId: z.string().nullable().optional(),
19
+ sourcePath: z.string().nullable().optional(),
20
+ chunkIndex: z.number().int().optional(),
21
+ totalChunks: z.number().int().optional(),
22
+ tags: z.array(z.string()).optional(),
23
+ createdAt: z.string().optional(),
24
+ updatedAt: z.string().nullable().optional(),
25
+ accessedAt: z.string().optional(),
26
+ expiresAt: z.string().nullable().optional(),
27
+ accessCount: z.number().int().optional(),
28
+ embeddingModel: z.string().nullable().optional(),
29
+ contentHash: z.string().nullable().optional(),
30
+ version: z.number().int().optional(),
31
+ });
7
32
 
8
33
  export const registerMemoryEditTool = (server: McpServer) => {
9
34
  createToolRegistrar(server)(
@@ -45,11 +70,9 @@ export const registerMemoryEditTool = (server: McpServer) => {
45
70
  intent: z.string().min(1).describe("Why you are editing this memory."),
46
71
  expectedVersion: z.number().int().min(1).optional(),
47
72
  }),
48
- outputSchema: z.object({
73
+ outputSchema: swarmToolOutputSchema({
49
74
  yourAgentId: z.string().optional(),
50
- success: z.boolean(),
51
- message: z.string(),
52
- memory: AgentMemorySchema.optional(),
75
+ memory: agentMemoryOutputSchema.optional(),
53
76
  changed: z.boolean().optional(),
54
77
  previousVersion: z.number().int().optional(),
55
78
  version: z.number().int().optional(),
@@ -61,25 +84,13 @@ export const registerMemoryEditTool = (server: McpServer) => {
61
84
  _meta,
62
85
  ) => {
63
86
  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
- };
87
+ return toolErr("Agent ID required. Are you registered in the swarm?");
72
88
  }
73
89
 
74
90
  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
- };
91
+ return toolErr("memoryId or key+scope required.", {
92
+ data: { yourAgentId: requestInfo.agentId },
93
+ });
83
94
  }
84
95
 
85
96
  try {
@@ -113,36 +124,24 @@ export const registerMemoryEditTool = (server: McpServer) => {
113
124
  }
114
125
  }
115
126
 
116
- return {
117
- content: [
118
- {
119
- type: "text",
120
- text: result.changed
121
- ? `Memory "${result.memory.id}" edited to version ${result.version}.`
122
- : `Memory "${result.memory.id}" unchanged.`,
127
+ return toolOk(
128
+ result.changed
129
+ ? `Memory "${result.memory.id}" edited to version ${result.version}.`
130
+ : `Memory "${result.memory.id}" unchanged.`,
131
+ {
132
+ data: {
133
+ yourAgentId: requestInfo.agentId,
134
+ memory: result.memory,
135
+ changed: result.changed,
136
+ previousVersion: result.previousVersion,
137
+ version: result.version,
123
138
  },
124
- ],
125
- structuredContent: {
126
- yourAgentId: requestInfo.agentId,
127
- success: true,
128
- message: result.changed
129
- ? `Memory edited to version ${result.version}.`
130
- : "Memory unchanged.",
131
- memory: result.memory,
132
- changed: result.changed,
133
- previousVersion: result.previousVersion,
134
- version: result.version,
135
139
  },
136
- };
140
+ );
137
141
  } catch (err) {
138
- return {
139
- content: [{ type: "text", text: `Memory edit failed: ${(err as Error).message}` }],
140
- structuredContent: {
141
- yourAgentId: requestInfo.agentId,
142
- success: false,
143
- message: `Memory edit failed: ${(err as Error).message}`,
144
- },
145
- };
142
+ return toolErr(`Memory edit failed: ${(err as Error).message}`, {
143
+ data: { yourAgentId: requestInfo.agentId },
144
+ });
146
145
  }
147
146
  },
148
147
  );
@@ -5,19 +5,44 @@ import { getMemoryStore } from "@/be/memory";
5
5
  import { canReadMemory } from "@/be/memory/access";
6
6
  import { getLinksForMemory, type MemoryLinksResult } from "@/be/memory/links-store";
7
7
  import { recordRetrievals } from "@/be/memory/raters/retrieval";
8
- import { createToolRegistrar } from "@/tools/utils";
8
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
9
9
  import type { AgentMemorySource } from "@/types";
10
- import { AgentMemorySchema } from "@/types";
10
+ import { AgentMemoryScopeSchema, AgentMemorySourceSchema } from "@/types";
11
11
 
12
12
  const NUDGE_ELIGIBLE_SOURCES: ReadonlySet<AgentMemorySource> = new Set(["manual", "file_index"]);
13
13
 
14
- const LinkedMemoryRefSchema = z.object({
14
+ // Loose, format-pin-free mirror of AgentMemorySchema for MCP output validation.
15
+ const agentMemoryOutputSchema = z.looseObject({
16
+ id: z.string().optional(),
17
+ agentId: z.string().nullable().optional(),
18
+ scope: AgentMemoryScopeSchema.optional(),
19
+ key: z.string().nullable().optional(),
20
+ name: z.string().optional(),
21
+ content: z.string().optional(),
22
+ summary: z.string().nullable().optional(),
23
+ source: AgentMemorySourceSchema.optional(),
24
+ sourceTaskId: z.string().nullable().optional(),
25
+ sourcePath: z.string().nullable().optional(),
26
+ chunkIndex: z.number().int().optional(),
27
+ totalChunks: z.number().int().optional(),
28
+ tags: z.array(z.string()).optional(),
29
+ createdAt: z.string().optional(),
30
+ updatedAt: z.string().nullable().optional(),
31
+ accessedAt: z.string().optional(),
32
+ expiresAt: z.string().nullable().optional(),
33
+ accessCount: z.number().int().optional(),
34
+ embeddingModel: z.string().nullable().optional(),
35
+ contentHash: z.string().nullable().optional(),
36
+ version: z.number().int().optional(),
37
+ });
38
+
39
+ const LinkedMemoryRefSchema = z.looseObject({
15
40
  id: z.string(),
16
41
  name: z.string(),
17
42
  scope: z.string(),
18
43
  });
19
44
 
20
- const MemoryLinkSchema = z.object({
45
+ const MemoryLinkSchema = z.looseObject({
21
46
  id: z.string(),
22
47
  linkType: z.string(),
23
48
  targetKind: z.string(),
@@ -36,7 +61,7 @@ const MemoryLinkSchema = z.object({
36
61
  ),
37
62
  });
38
63
 
39
- const MemoryBacklinkSchema = z.object({
64
+ const MemoryBacklinkSchema = z.looseObject({
40
65
  id: z.string(),
41
66
  linkType: z.string(),
42
67
  strength: z.number(),
@@ -63,11 +88,9 @@ export const registerMemoryGetTool = (server: McpServer) => {
63
88
  "Why you are retrieving this memory. Required. E.g. 'need full details of the auth fix pattern'.",
64
89
  ),
65
90
  }),
66
- outputSchema: z.object({
91
+ outputSchema: swarmToolOutputSchema({
67
92
  yourAgentId: z.string().optional(),
68
- success: z.boolean(),
69
- message: z.string(),
70
- memory: AgentMemorySchema.optional(),
93
+ memory: agentMemoryOutputSchema.optional(),
71
94
  links: z
72
95
  .array(MemoryLinkSchema)
73
96
  .optional()
@@ -84,25 +107,13 @@ export const registerMemoryGetTool = (server: McpServer) => {
84
107
  const memoryForAuth = store.peek(memoryId);
85
108
 
86
109
  if (!memoryForAuth) {
87
- return {
88
- content: [{ type: "text", text: `Memory "${memoryId}" not found.` }],
89
- structuredContent: {
90
- yourAgentId: requestInfo.agentId,
91
- success: false,
92
- message: `Memory "${memoryId}" not found.`,
93
- },
94
- };
110
+ return toolErr(`Memory "${memoryId}" not found.`, {
111
+ data: { yourAgentId: requestInfo.agentId },
112
+ });
95
113
  }
96
114
 
97
115
  if (!canReadMemory(memoryForAuth, requestInfo.agentId)) {
98
- return {
99
- content: [{ type: "text", text: "Not authorized" }],
100
- structuredContent: {
101
- yourAgentId: requestInfo.agentId,
102
- success: false,
103
- message: "Not authorized",
104
- },
105
- };
116
+ return toolErr("Not authorized", { data: { yourAgentId: requestInfo.agentId } });
106
117
  }
107
118
 
108
119
  const memory = store.get(memoryId)!;
@@ -146,23 +157,16 @@ export const registerMemoryGetTool = (server: McpServer) => {
146
157
  ? `\n\n[${linkBlocks.links.length} outgoing link(s), ${linkBlocks.backlinks.length} backlink(s) — see structured output]`
147
158
  : "";
148
159
 
149
- return {
150
- content: [
151
- {
152
- type: "text",
153
- text: `Memory "${memory.name}" retrieved.\n\n${memory.content}${linksSummary}`,
154
- },
155
- ],
156
- structuredContent: {
160
+ return toolOk(`Memory "${memory.name}" retrieved.`, {
161
+ details: `${memory.content}${linksSummary}`,
162
+ data: {
157
163
  yourAgentId: requestInfo.agentId,
158
- success: true,
159
- message: `Memory "${memory.name}" retrieved.`,
160
164
  memory,
161
165
  links: linkBlocks.links,
162
166
  backlinks: linkBlocks.backlinks,
163
167
  rateHint,
164
168
  },
165
- };
169
+ });
166
170
  },
167
171
  );
168
172
  };
@@ -1,7 +1,7 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import * as z from "zod";
3
3
  import { REFERENCES_SOURCE_MAX_LENGTH, sanitizeReferencesSource } from "@/be/memory/raters/types";
4
- import { createToolRegistrar } from "@/tools/utils";
4
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
5
5
  import { getApiKey } from "@/utils/api-key";
6
6
  import { getMcpBaseUrl } from "@/utils/constants";
7
7
 
@@ -58,37 +58,25 @@ export const registerMemoryRateTool = (server: McpServer) => {
58
58
  .optional()
59
59
  .describe(REFERENCES_SOURCE_DESCRIPTION),
60
60
  }),
61
- outputSchema: z.object({
62
- success: z.boolean(),
63
- message: z.string(),
64
- }),
61
+ outputSchema: swarmToolOutputSchema(),
65
62
  },
66
63
  async ({ id, useful, note, referencesSource }, requestInfo, _meta) => {
67
64
  if (!requestInfo.agentId) {
68
- const msg = "Agent ID required. Are you registered in the swarm?";
69
- return {
70
- content: [{ type: "text", text: msg }],
71
- structuredContent: { success: false, message: msg },
72
- };
65
+ return toolErr("Agent ID required. Are you registered in the swarm?");
73
66
  }
74
67
  if (!requestInfo.sourceTaskId) {
75
- const msg = "memory_rate must be called from within a task — no source task ID was found.";
76
- return {
77
- content: [{ type: "text", text: msg }],
78
- structuredContent: { success: false, message: msg },
79
- };
68
+ return toolErr(
69
+ "memory_rate must be called from within a task — no source task ID was found.",
70
+ );
80
71
  }
81
72
 
82
73
  let cleanedReferencesSource: string | undefined;
83
74
  if (referencesSource !== undefined) {
84
75
  const cleaned = sanitizeReferencesSource(referencesSource);
85
76
  if (cleaned === null) {
86
- const msg =
87
- "referencesSource must not contain NUL bytes or strip to empty after control-char removal.";
88
- return {
89
- content: [{ type: "text", text: msg }],
90
- structuredContent: { success: false, message: msg },
91
- };
77
+ return toolErr(
78
+ "referencesSource must not contain NUL bytes or strip to empty after control-char removal.",
79
+ );
92
80
  }
93
81
  cleanedReferencesSource = cleaned;
94
82
  }
@@ -120,10 +108,7 @@ export const registerMemoryRateTool = (server: McpServer) => {
120
108
  });
121
109
 
122
110
  if (response.status === 409) {
123
- return {
124
- content: [{ type: "text", text: DUPLICATE_MESSAGE }],
125
- structuredContent: { success: false, message: DUPLICATE_MESSAGE },
126
- };
111
+ return toolErr(DUPLICATE_MESSAGE);
127
112
  }
128
113
 
129
114
  if (response.status === 400) {
@@ -137,31 +122,16 @@ export const registerMemoryRateTool = (server: McpServer) => {
137
122
  const msg = serverError
138
123
  ? `Memory rating rejected: ${serverError}. The memory must have been retrieved by this task before it can be rated.`
139
124
  : "Memory rating rejected. The memory must have been retrieved by this task before it can be rated.";
140
- return {
141
- content: [{ type: "text", text: msg }],
142
- structuredContent: { success: false, message: msg },
143
- };
125
+ return toolErr(msg);
144
126
  }
145
127
 
146
128
  if (!response.ok) {
147
- const msg = `Memory rating failed (HTTP ${response.status}).`;
148
- return {
149
- content: [{ type: "text", text: msg }],
150
- structuredContent: { success: false, message: msg },
151
- };
129
+ return toolErr(`Memory rating failed (HTTP ${response.status}).`);
152
130
  }
153
131
 
154
- const successMsg = `Memory ${id} rated as ${useful ? "useful" : "not useful"}.`;
155
- return {
156
- content: [{ type: "text", text: successMsg }],
157
- structuredContent: { success: true, message: successMsg },
158
- };
132
+ return toolOk(`Memory ${id} rated as ${useful ? "useful" : "not useful"}.`);
159
133
  } catch (err) {
160
- const msg = `Memory rating failed: ${(err as Error).message}`;
161
- return {
162
- content: [{ type: "text", text: msg }],
163
- structuredContent: { success: false, message: msg },
164
- };
134
+ return toolErr(`Memory rating failed: ${(err as Error).message}`);
165
135
  }
166
136
  },
167
137
  );
@@ -6,7 +6,7 @@ import { CANDIDATE_SET_MULTIPLIER } from "@/be/memory/constants";
6
6
  import { expandCandidatesWithGraph } from "@/be/memory/graph-expansion";
7
7
  import { recordRetrievals } from "@/be/memory/raters/retrieval";
8
8
  import { rerank } from "@/be/memory/reranker";
9
- import { createToolRegistrar } from "@/tools/utils";
9
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
10
10
  import type { AgentMemorySource } from "@/types";
11
11
  import { AgentMemoryScopeSchema, AgentMemorySourceSchema } from "@/types";
12
12
 
@@ -16,30 +16,51 @@ function rateHintFor(memoryId: string): string {
16
16
  return `memory_rate(id="${memoryId}", useful=true|false)`;
17
17
  }
18
18
 
19
- export const memorySearchOutputSchema = z.object({
19
+ type MemorySearchResult = {
20
+ id: string;
21
+ name: string;
22
+ summary: string | null;
23
+ source: string;
24
+ scope: string;
25
+ similarity?: number;
26
+ retrievalSource?: string;
27
+ tags?: string[];
28
+ createdAt: string;
29
+ rateHint?: string;
30
+ };
31
+
32
+ function renderResults(results: MemorySearchResult[]): string | undefined {
33
+ if (results.length === 0) return undefined;
34
+ return results
35
+ .map((r) => {
36
+ const score = typeof r.similarity === "number" ? ` score=${r.similarity.toFixed(3)}` : "";
37
+ const summary = r.summary ? ` — ${r.summary}` : "";
38
+ return `- ${r.id} [${r.source}/${r.scope}]${score}${summary}`;
39
+ })
40
+ .join("\n");
41
+ }
42
+
43
+ export const memorySearchOutputSchema = swarmToolOutputSchema({
20
44
  // Plain string, NOT .uuid(): agents may join with custom IDs (AGENT_ID env /
21
45
  // join-swarm agentId), and a UUID constraint here makes the response fail MCP
22
46
  // output validation after the handler already ran.
23
47
  yourAgentId: z.string().optional(),
24
- success: z.boolean(),
25
- message: z.string(),
26
48
  results: z
27
49
  .array(
28
- z.object({
29
- id: z.string().uuid(),
30
- name: z.string(),
31
- summary: z.string().nullable(),
32
- source: AgentMemorySourceSchema,
33
- scope: AgentMemoryScopeSchema,
50
+ z.looseObject({
51
+ id: z.string().optional(),
52
+ name: z.string().optional(),
53
+ summary: z.string().nullable().optional(),
54
+ source: AgentMemorySourceSchema.optional(),
55
+ scope: AgentMemoryScopeSchema.optional(),
34
56
  similarity: z.number().optional(),
35
57
  retrievalSource: z.enum(["vec", "fts", "hybrid", "fallback", "graph"]).optional(),
36
58
  tags: z.array(z.string()).optional(),
37
- createdAt: z.string(),
59
+ createdAt: z.string().optional(),
38
60
  rateHint: z.string().optional(),
39
61
  }),
40
62
  )
41
63
  .optional(),
42
- _ratingNudge: z.string().optional(),
43
64
  });
44
65
 
45
66
  export const registerMemorySearchTool = (server: McpServer) => {
@@ -72,14 +93,7 @@ export const registerMemorySearchTool = (server: McpServer) => {
72
93
  },
73
94
  async ({ query, intent, scope, limit, source }, requestInfo, _meta) => {
74
95
  if (!requestInfo.agentId) {
75
- return {
76
- content: [{ type: "text", text: "Agent ID required for memory search." }],
77
- structuredContent: {
78
- yourAgentId: undefined,
79
- success: false,
80
- message: "Agent ID required. Are you registered in the swarm?",
81
- },
82
- };
96
+ return toolErr("Agent ID required. Are you registered in the swarm?");
83
97
  }
84
98
 
85
99
  const agent = getAgentById(requestInfo.agentId);
@@ -146,25 +160,12 @@ export const registerMemorySearchTool = (server: McpServer) => {
146
160
  : {}),
147
161
  }));
148
162
 
149
- const nudgeCount = mapped.filter((r) => r.rateHint).length;
150
- const _ratingNudge =
151
- nudgeCount > 0 ? "Rate memories that help or mislead you with memory_rate." : undefined;
152
-
153
- return {
154
- content: [
155
- {
156
- type: "text",
157
- text: `Found ${mapped.length} memories matching "${query}".`,
158
- },
159
- ],
160
- structuredContent: {
161
- yourAgentId: requestInfo.agentId,
162
- success: true,
163
- message: `Found ${mapped.length} memories matching "${query}".`,
164
- results: mapped,
165
- _ratingNudge,
166
- },
167
- };
163
+ // The conditional rating steer lives in the central NUDGES map
164
+ // (src/tools/utils.ts), keyed off rateHint presence in the results.
165
+ return toolOk(`Found ${mapped.length} memories matching "${query}".`, {
166
+ details: renderResults(mapped),
167
+ data: { yourAgentId: requestInfo.agentId, results: mapped },
168
+ });
168
169
  }
169
170
 
170
171
  // Fallback: list recent memories (no OPENAI_API_KEY and no FTS hit)
@@ -185,20 +186,13 @@ export const registerMemorySearchTool = (server: McpServer) => {
185
186
  createdAt: r.createdAt,
186
187
  }));
187
188
 
188
- return {
189
- content: [
190
- {
191
- type: "text",
192
- text: `Embedding unavailable. Showing ${mapped.length} most recent memories.`,
193
- },
194
- ],
195
- structuredContent: {
196
- yourAgentId: requestInfo.agentId,
197
- success: true,
198
- message: `Embedding unavailable (no OPENAI_API_KEY). Showing ${mapped.length} most recent memories.`,
199
- results: mapped,
189
+ return toolOk(
190
+ `Embedding unavailable (no OPENAI_API_KEY). Showing ${mapped.length} most recent memories.`,
191
+ {
192
+ details: renderResults(mapped),
193
+ data: { yourAgentId: requestInfo.agentId, results: mapped },
200
194
  },
201
- };
195
+ );
202
196
  },
203
197
  );
204
198
  };