@desplega.ai/agent-swarm 1.129.0 → 1.131.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 (226) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-kfv2dawe.js → actions-w53mbns9.js} +11 -11
  3. package/dist/{anthropic-messages-3xgme8my.js → anthropic-messages-rjmd2e7n.js} +5 -5
  4. package/dist/{app-q8vjk6e8.js → app-m9gwqsqv.js} +8 -8
  5. package/dist/{artifact-hg4t1nx7.js → artifact-jysj3wrg.js} +2 -2
  6. package/dist/{assistant-g037r345.js → assistant-bp65m6f3.js} +13 -13
  7. package/dist/{azure-openai-responses-xa4sh9f6.js → azure-openai-responses-c0yjmbfd.js} +8 -5
  8. package/dist/{boot-reembed-18pzsrxa.js → boot-reembed-62p0at2k.js} +6 -6
  9. package/dist/{boot-reembed-wpks2cj8.js → boot-reembed-xmfp6wdh.js} +7 -7
  10. package/dist/{boot-scrub-logs-n7szd57r.js → boot-scrub-logs-rr8q2dms.js} +5 -5
  11. package/dist/{claude-adapter-qz4r0ajt.js → claude-adapter-2y47mrkd.js} +9 -9
  12. package/dist/{cli-mhjnbgb6.js → cli-0rcyq6d9.js} +450 -186
  13. package/dist/{cli-ttkmehy0.js → cli-2q72qz2s.js} +274 -25
  14. package/dist/{cli-gztgc3hz.js → cli-2wadx7p2.js} +2 -2
  15. package/dist/cli-3fj60etf.js +153 -0
  16. package/dist/{cli-7ecgm5v0.js → cli-3kf51j15.js} +1 -1
  17. package/dist/{cli-vgexpfsr.js → cli-57khth04.js} +6 -3
  18. package/dist/{cli-2mbe7vk0.js → cli-5dsbcjjw.js} +1 -1
  19. package/dist/{cli-etr62zy6.js → cli-5kx36evn.js} +2 -2
  20. package/dist/{cli-v2tr6amf.js → cli-5n6e5yfn.js} +30 -8
  21. package/dist/{cli-hx02s9zq.js → cli-5v4rw6yd.js} +2 -2
  22. package/dist/{cli-v37yr6mf.js → cli-5ze9rv97.js} +4 -4
  23. package/dist/{cli-ch7t5v7n.js → cli-6map995v.js} +9 -4
  24. package/dist/{cli-h0457a67.js → cli-70xqj0z3.js} +3 -3
  25. package/dist/{cli-kk4f9r17.js → cli-72q8m8gk.js} +8 -6
  26. package/dist/{cli-7padk69a.js → cli-78xwvkhj.js} +2 -2
  27. package/dist/{cli-dxtxacy7.js → cli-9dr5qzc0.js} +45 -8
  28. package/dist/{cli-17zxdgsq.js → cli-a40rnf71.js} +6 -6
  29. package/dist/{cli-t53vnnxz.js → cli-a4jzdpa3.js} +2514 -1055
  30. package/dist/{cli-w10fkrf1.js → cli-akdvwc9v.js} +354 -115
  31. package/dist/{cli-1qkk5er0.js → cli-bmze986d.js} +1 -1
  32. package/dist/{cli-ga12dc1d.js → cli-bqw0mt1n.js} +3 -3
  33. package/dist/{cli-0sf92efp.js → cli-cdeg08wx.js} +1 -1
  34. package/dist/{cli-a8ynhkyj.js → cli-cvgjwnh1.js} +17 -15
  35. package/dist/{cli-9fxg3v5m.js → cli-d2tfkcga.js} +4 -4
  36. package/dist/{cli-nhcd7x43.js → cli-d3x3x1c9.js} +2 -2
  37. package/dist/{cli-6nh2qxvh.js → cli-darcwax3.js} +1 -1
  38. package/dist/{cli-yjbgmysx.js → cli-e7ckcg4v.js} +12 -12
  39. package/dist/{cli-4n2gcjpd.js → cli-efxfnq6q.js} +4 -3
  40. package/dist/{cli-z9xqqhfk.js → cli-er3a4bb0.js} +1 -1
  41. package/dist/{cli-xg2eezyv.js → cli-f1am9szv.js} +1 -1
  42. package/dist/{cli-xy4cwsm9.js → cli-fywms69x.js} +1 -1
  43. package/dist/{cli-33jj76y8.js → cli-g6b8x1h8.js} +1 -1
  44. package/dist/{cli-epsvdckx.js → cli-gm9cbhbq.js} +20 -10
  45. package/dist/{cli-rkndnn90.js → cli-k9qkf1hw.js} +6 -4
  46. package/dist/{cli-zejvt395.js → cli-kh3ba2zf.js} +1 -1
  47. package/dist/{cli-gb25p1h2.js → cli-nm5gtp1x.js} +2 -2
  48. package/dist/{cli-akxnpx17.js → cli-pm6xbh84.js} +1829 -1629
  49. package/dist/{cli-2k0ztbfp.js → cli-psh3c4va.js} +1 -1
  50. package/dist/{cli-39vgrsep.js → cli-qv61hp37.js} +2 -2
  51. package/dist/{cli-hv2fndhm.js → cli-r6kqqbj0.js} +6 -4
  52. package/dist/{cli-1y1cm570.js → cli-rzbpmxdr.js} +1 -1
  53. package/dist/{cli-mmrk00vp.js → cli-t1xze5qh.js} +1 -1
  54. package/dist/{cli-g252a9ky.js → cli-t55yw3a1.js} +2 -2
  55. package/dist/{cli-7bz8dzqa.js → cli-t76vw5db.js} +1184 -1522
  56. package/dist/{cli-4n4mdv21.js → cli-xpxde7rm.js} +7 -3
  57. package/dist/{cli-fpaa5k2q.js → cli-yw8vghx2.js} +54 -18
  58. package/dist/cli-zsspvvm2.js +490 -0
  59. package/dist/cli.js +27 -25
  60. package/dist/{codex-adapter-7v6t7ff6.js → codex-adapter-d24q75wk.js} +7 -7
  61. package/dist/{codex-hook-amndawyb.js → codex-hook-hq54t9ft.js} +2 -2
  62. package/dist/{codex-session-runner-e7j4khe2.js → codex-session-runner-g50vcsex.js} +7 -7
  63. package/dist/{commands-ex0k5tbf.js → commands-c3nrc5hg.js} +5 -5
  64. package/dist/{db-df7jatfc.js → db-nt7fg3tw.js} +5 -5
  65. package/dist/{google-generative-ai-y42hnw9p.js → google-generative-ai-hysrd8qx.js} +7 -5
  66. package/dist/{google-vertex-4sg66gb6.js → google-vertex-p5arrga0.js} +7 -5
  67. package/dist/{handlers-1j2cfqt2.js → handlers-fkr6swat.js} +13 -13
  68. package/dist/{hook-nx9a0mj3.js → hook-77wpvnjc.js} +7 -7
  69. package/dist/{hook-w6yaf6sy.js → hook-g019yehy.js} +8 -8
  70. package/dist/{http-4tz5h8wg.js → http-jewj0syk.js} +2993 -716
  71. package/dist/{index-0bpkzb09.js → index-070v4eyb.js} +3 -3
  72. package/dist/{index-0s67qv7h.js → index-6gm5he8h.js} +11 -11
  73. package/dist/{index-35gtv6gj.js → index-7n2xpbd4.js} +310 -40
  74. package/dist/{index-ker3gccb.js → index-9znhar3x.js} +4 -4
  75. package/dist/{index-5n2c8yay.js → index-hase6zbe.js} +2 -2
  76. package/dist/{index-kcf3tm9h.js → index-hfvggd0z.js} +12 -12
  77. package/dist/{index-7c0jqna0.js → index-hp1kdbjj.js} +13 -13
  78. package/dist/{keepalive-3j4a9168.js → keepalive-j0fjvqfd.js} +7 -7
  79. package/dist/{lead-6kpevymb.js → lead-1n8x30xe.js} +33 -33
  80. package/dist/{maintenance-m1k82ean.js → maintenance-gvev11sa.js} +7 -7
  81. package/dist/{mistral-conversations-bjkdfb6z.js → mistral-conversations-81fwav0j.js} +6 -6
  82. package/dist/{oauth-refresh-sweep-881k8e4q.js → oauth-refresh-sweep-s9ecsvh0.js} +6 -6
  83. package/dist/{onboard-c0ykffjn.js → onboard-pvm5b38w.js} +2 -2
  84. package/dist/{openai-codex-responses-xetseqvt.js → openai-codex-responses-5g27pd6f.js} +43 -23
  85. package/dist/{openai-completions-5r2g5axa.js → openai-completions-3vkmfz2a.js} +55 -11
  86. package/dist/{openai-responses-ce67hd23.js → openai-responses-dg4t7j7a.js} +8 -5
  87. package/dist/{openrouter-images-pzfp22jb.js → openrouter-images-g3gm8931.js} +1 -1
  88. package/dist/{otel-impl-sqagjerv.js → otel-impl-p6jvgd9c.js} +6 -4
  89. package/dist/{otel-3mp81ppd.js → otel-nqa12wf3.js} +2 -2
  90. package/dist/{pi-mono-adapter-k584k16g.js → pi-mono-adapter-t091s27g.js} +17117 -7517
  91. package/dist/{pricing-refresh-y82whbf9.js → pricing-refresh-k49rcyed.js} +7 -7
  92. package/dist/{rbac-roles-nvkqmzyd.js → rbac-roles-30pspvy7.js} +7 -7
  93. package/dist/{rbac-roles-4ht8gegc.js → rbac-roles-cr80g96t.js} +6 -6
  94. package/dist/{render-v2-wvqdgvvp.js → render-v2-xm457ng1.js} +8 -8
  95. package/dist/{seed-pricing-fy3rxhde.js → seed-pricing-yhpv35fr.js} +6 -6
  96. package/dist/{setup-ak5cnc6f.js → setup-nytnmwwr.js} +2 -2
  97. package/dist/{worker-d8769q8a.js → worker-msytr2cw.js} +33 -33
  98. package/openapi.json +34039 -11036
  99. package/package.json +8 -6
  100. package/src/apps/definition.ts +368 -26
  101. package/src/apps/row-store.ts +66 -10
  102. package/src/apps/schema-migrate.ts +95 -1
  103. package/src/apps/store.ts +13 -4
  104. package/src/apps/sync-run-as.ts +18 -0
  105. package/src/apps/sync.ts +934 -0
  106. package/src/apps/version.ts +16 -2
  107. package/src/assets/key.ts +8 -1
  108. package/src/be/asset-key-audit.ts +3 -1
  109. package/src/be/db-queries/mcp-oauth.ts +297 -24
  110. package/src/be/db.ts +42 -1
  111. package/src/be/migrations/129_asset_keys_apps_scripts.sql +161 -0
  112. package/src/be/scripts/db.ts +5 -2
  113. package/src/be/scripts/typecheck.ts +1 -0
  114. package/src/be/seed-scripts/catalog/app-sync-run.ts +32 -0
  115. package/src/be/seed-scripts/catalog/github-issues-pull.ts +102 -0
  116. package/src/be/seed-scripts/index.ts +18 -0
  117. package/src/be/seed-skills/index.ts +7 -0
  118. package/src/http/active-sessions.ts +26 -18
  119. package/src/http/agents.ts +94 -27
  120. package/src/http/api-keys.ts +91 -17
  121. package/src/http/approval-requests.ts +87 -10
  122. package/src/http/apps.ts +361 -53
  123. package/src/http/assets.ts +165 -31
  124. package/src/http/budgets.ts +7 -5
  125. package/src/http/codex-oauth-keep-warm.ts +21 -3
  126. package/src/http/config.ts +46 -16
  127. package/src/http/context.ts +33 -6
  128. package/src/http/ecosystem.ts +20 -6
  129. package/src/http/events.ts +24 -9
  130. package/src/http/favorites.ts +20 -6
  131. package/src/http/fs.ts +60 -17
  132. package/src/http/heartbeat.ts +18 -4
  133. package/src/http/inbox-state.ts +12 -6
  134. package/src/http/integrations.ts +25 -5
  135. package/src/http/kv.ts +36 -15
  136. package/src/http/mcp-bridge.ts +5 -1
  137. package/src/http/mcp-oauth.ts +332 -17
  138. package/src/http/mcp-servers.ts +56 -18
  139. package/src/http/memory.ts +282 -29
  140. package/src/http/metrics.ts +80 -17
  141. package/src/http/oauth-callback.ts +10 -4
  142. package/src/http/oauth-generic.ts +5 -1
  143. package/src/http/oauth-locks.ts +6 -3
  144. package/src/http/openapi.ts +57 -9
  145. package/src/http/page-proxy.ts +25 -5
  146. package/src/http/pages-public.ts +37 -20
  147. package/src/http/pages.ts +93 -28
  148. package/src/http/poll.ts +89 -5
  149. package/src/http/pricing.ts +9 -6
  150. package/src/http/prompt-templates.ts +85 -21
  151. package/src/http/route-def.ts +67 -4
  152. package/src/http/schedules.ts +63 -14
  153. package/src/http/script-connection-proxy.ts +30 -4
  154. package/src/http/script-connections.ts +393 -43
  155. package/src/http/script-runs.ts +73 -19
  156. package/src/http/scripts.ts +257 -39
  157. package/src/http/session-data.ts +87 -14
  158. package/src/http/sessions.ts +80 -5
  159. package/src/http/skills.ts +115 -35
  160. package/src/http/stats.ts +94 -13
  161. package/src/http/task-templates.ts +6 -4
  162. package/src/http/tasks.ts +230 -61
  163. package/src/http/trackers/jira.ts +90 -30
  164. package/src/http/trackers/linear.ts +46 -12
  165. package/src/http/users.ts +162 -25
  166. package/src/http/utils.ts +12 -2
  167. package/src/http/webhooks.ts +30 -16
  168. package/src/http/workflow-events.ts +18 -5
  169. package/src/http/workflows.ts +128 -39
  170. package/src/http/x.ts +37 -6
  171. package/src/oauth/ensure-mcp-token.ts +16 -1
  172. package/src/oauth/mcp-wrapper.ts +281 -26
  173. package/src/providers/pi-mono-adapter.ts +1 -1
  174. package/src/scripts-runtime/credential-broker/README.md +1 -1
  175. package/src/scripts-runtime/credential-broker/fetch-patch.ts +12 -2
  176. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  177. package/src/scripts-runtime/stdlib/fetch.ts +6 -0
  178. package/src/scripts-runtime/types/stdlib.d.ts +1 -0
  179. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
  180. package/src/server.ts +2 -0
  181. package/src/tests/apps-rbac.test.ts +110 -0
  182. package/src/tests/apps-spike2.test.ts +4 -1
  183. package/src/tests/apps-sync-engine.test.ts +2540 -0
  184. package/src/tests/apps-sync.test.ts +1627 -0
  185. package/src/tests/asset-key-api.test.ts +48 -2
  186. package/src/tests/asset-key-invariants.test.ts +92 -0
  187. package/src/tests/asset-key-migration.test.ts +174 -8
  188. package/src/tests/asset-key-normalization.test.ts +2 -0
  189. package/src/tests/credential-broker.test.ts +27 -2
  190. package/src/tests/mcp-oauth-dcr-reuse.test.ts +743 -0
  191. package/src/tests/mcp-oauth-ensure-token.test.ts +45 -0
  192. package/src/tests/mcp-oauth-manual-client.test.ts +135 -2
  193. package/src/tests/mcp-oauth-queries.test.ts +153 -0
  194. package/src/tests/mcp-oauth-wrapper.test.ts +432 -0
  195. package/src/tests/memory-http-recall-gating.test.ts +2 -0
  196. package/src/tests/openapi-response-contract.test.ts +138 -0
  197. package/src/tests/rbac-admission-e2e.test.ts +68 -0
  198. package/src/tests/script-connections.test.ts +3 -0
  199. package/src/tests/scripts-runtime-fetch.test.ts +121 -0
  200. package/src/tests/scripts-runtime-secret-egress.test.ts +4 -2
  201. package/src/tests/seed-scripts.test.ts +2 -2
  202. package/src/tests/swarm-tool-result-gate.test.ts +32 -0
  203. package/src/tests/task-working-dir.test.ts +8 -4
  204. package/src/tests/whoami-route.test.ts +127 -0
  205. package/src/tests/workflow-engine-v2.test.ts +80 -7
  206. package/src/tests/workflow-swarm-script.test.ts +104 -0
  207. package/src/tools/app-get.ts +10 -2
  208. package/src/tools/app-rollback.ts +1 -0
  209. package/src/tools/app-sync.ts +112 -0
  210. package/src/tools/script-common.ts +20 -0
  211. package/src/tools/tool-config.ts +2 -1
  212. package/src/tools/utils.ts +11 -0
  213. package/src/tools/workflows/create-workflow.ts +4 -1
  214. package/src/types.ts +1394 -1206
  215. package/src/utils/template.ts +8 -1
  216. package/src/utils/zod-openapi.ts +11 -0
  217. package/src/workflows/engine.ts +27 -4
  218. package/src/workflows/executors/swarm-script.ts +28 -0
  219. package/src/workflows/retry-poller.ts +19 -2
  220. package/templates/skills/apps/content.md +94 -5
  221. package/templates/skills/asset-namespaces/content.md +2 -2
  222. package/templates/skills/scheduled-task-resilience/SKILL.md +102 -0
  223. package/templates/skills/scheduled-task-resilience/config.json +14 -0
  224. package/templates/skills/scheduled-task-resilience/content.md +97 -0
  225. package/dist/cli-7wmybrt5.js +0 -115
  226. package/dist/cli-d91pvmq1.js +0 -14
@@ -20,12 +20,27 @@ import { rerank } from "../be/memory/reranker";
20
20
  import { getRetrievalsForAgent, hasRetrievalForTask } from "../be/memory/retrieval-store";
21
21
  import { getUsefulnessStats } from "../be/memory/usefulness-stats";
22
22
  import { shouldPersistAutomaticTaskMemory } from "../memory/automatic-task-gate";
23
- import { AgentMemoryScopeSchema, AgentMemorySourceSchema } from "../types";
23
+ import { AgentMemorySchema, AgentMemoryScopeSchema, AgentMemorySourceSchema } from "../types";
24
24
  import { route } from "./route-def";
25
- import { json, jsonError, parseQueryParams } from "./utils";
25
+ import { jsonError, parseQueryParams } from "./utils";
26
+
27
+ // ─── Response Schemas ────────────────────────────────────────────────────────
28
+
29
+ // Mirrors `MemoryRetrievalSource` (src/be/memory/types.ts) — the arm that
30
+ // surfaced a search candidate. Shared by the search and list result shapes.
31
+ const MemoryRetrievalSourceSchema = z.enum(["vec", "fts", "hybrid", "fallback", "graph"]);
26
32
 
27
33
  // ─── Route Definitions ───────────────────────────────────────────────────────
28
34
 
35
+ // Shared shape across the three 202 sends: (1) automatic-task-memory skip,
36
+ // (2) single-chunk re-index of an existing sourcePath, (3) fresh batch queue.
37
+ const IndexMemoryResponseSchema = z.object({
38
+ queued: z.boolean(),
39
+ memoryIds: z.array(z.string()),
40
+ skipped: z.string().optional(),
41
+ edited: z.boolean().optional(),
42
+ });
43
+
29
44
  const indexMemory = route({
30
45
  method: "post",
31
46
  path: "/api/memory/index",
@@ -45,11 +60,24 @@ const indexMemory = route({
45
60
  contextKey: z.string().optional(),
46
61
  }),
47
62
  responses: {
48
- 202: { description: "Content queued for embedding" },
63
+ 202: { description: "Content queued for embedding", schema: IndexMemoryResponseSchema },
49
64
  400: { description: "Validation error" },
50
65
  },
51
66
  });
52
67
 
68
+ const MemorySearchResultItemSchema = z.object({
69
+ id: z.string(),
70
+ name: z.string(),
71
+ content: z.string(),
72
+ similarity: z.number(),
73
+ rawSimilarity: z.number().optional(),
74
+ compositeScore: z.number().optional(),
75
+ retrievalSource: MemoryRetrievalSourceSchema.optional(),
76
+ source: AgentMemorySourceSchema,
77
+ scope: AgentMemoryScopeSchema,
78
+ tags: z.array(z.string()),
79
+ });
80
+
53
81
  const searchMemory = route({
54
82
  method: "post",
55
83
  path: "/api/memory/search",
@@ -71,11 +99,24 @@ const searchMemory = route({
71
99
  source: z.enum(["manual", "file_index", "session_summary", "task_completion"]).optional(),
72
100
  }),
73
101
  responses: {
74
- 200: { description: "Search results" },
102
+ 200: {
103
+ description: "Search results",
104
+ schema: z.object({ results: z.array(MemorySearchResultItemSchema) }),
105
+ },
75
106
  400: { description: "Missing query or agent ID" },
76
107
  },
77
108
  });
78
109
 
110
+ // Mirrors `MemoryEditResult` (src/be/memory/types.ts) — `store.edit()`'s
111
+ // return value, sent verbatim.
112
+ const MemoryEditResultSchema = z.object({
113
+ memory: AgentMemorySchema,
114
+ changed: z.boolean(),
115
+ previousVersion: z.number(),
116
+ version: z.number(),
117
+ contentHash: z.string(),
118
+ });
119
+
79
120
  const editMemory = route({
80
121
  method: "post",
81
122
  path: "/api/memory/edit",
@@ -96,7 +137,7 @@ const editMemory = route({
96
137
  expectedVersion: z.number().int().min(1).optional(),
97
138
  }),
98
139
  responses: {
99
- 200: { description: "Memory edited" },
140
+ 200: { description: "Memory edited", schema: MemoryEditResultSchema },
100
141
  400: { description: "Validation error" },
101
142
  404: { description: "Memory not found" },
102
143
  409: { description: "Version conflict" },
@@ -119,10 +160,39 @@ const reEmbedMemory = route({
119
160
  batchSize: z.number().int().min(1).max(100).default(20).describe("Memories per batch"),
120
161
  }),
121
162
  responses: {
122
- 202: { description: "Re-embedding started" },
163
+ 202: {
164
+ description: "Re-embedding started",
165
+ schema: z.object({ started: z.boolean(), totalMemories: z.number() }),
166
+ },
123
167
  },
124
168
  });
125
169
 
170
+ // Shared result item across both listMemory branches: the semantic-search
171
+ // branch (query set) populates similarity/rawSimilarity/compositeScore/
172
+ // retrievalSource; the plain-list branch (query empty) omits them.
173
+ const MemoryListResultItemSchema = z.object({
174
+ id: z.string(),
175
+ name: z.string(),
176
+ content: z.string(),
177
+ agentId: z.string().nullable(),
178
+ scope: AgentMemoryScopeSchema,
179
+ source: AgentMemorySourceSchema,
180
+ similarity: z.number().optional(),
181
+ rawSimilarity: z.number().optional(),
182
+ compositeScore: z.number().optional(),
183
+ retrievalSource: MemoryRetrievalSourceSchema.optional(),
184
+ createdAt: z.string(),
185
+ accessedAt: z.string(),
186
+ accessCount: z.number(),
187
+ expiresAt: z.string().nullable(),
188
+ embeddingModel: z.string().nullable(),
189
+ sourceTaskId: z.string().nullable(),
190
+ sourcePath: z.string().nullable(),
191
+ chunkIndex: z.number(),
192
+ totalChunks: z.number(),
193
+ tags: z.array(z.string()),
194
+ });
195
+
126
196
  const listMemory = route({
127
197
  method: "post",
128
198
  path: "/api/memory/list",
@@ -150,11 +220,56 @@ const listMemory = route({
150
220
  offset: z.number().int().min(0).default(0),
151
221
  }),
152
222
  responses: {
153
- 200: { description: "Memory list / search results" },
223
+ 200: {
224
+ description: "Memory list / search results",
225
+ schema: z.object({
226
+ results: z.array(MemoryListResultItemSchema),
227
+ total: z.number(),
228
+ limit: z.number(),
229
+ offset: z.number(),
230
+ mode: z.enum(["semantic", "list"]),
231
+ }),
232
+ },
154
233
  400: { description: "Validation error" },
155
234
  },
156
235
  });
157
236
 
237
+ // Mirrors `MemoryVecPopulateStats` (src/be/memory/types.ts).
238
+ const MemoryVecPopulateStatsSchema = z.object({
239
+ attempted: z.number(),
240
+ inserted: z.number(),
241
+ skippedInvalidDimensions: z.number(),
242
+ failed: z.number(),
243
+ beforeCount: z.number(),
244
+ afterCount: z.number(),
245
+ });
246
+
247
+ // Mirrors `MemoryHealth` (src/be/memory/types.ts) — `store.getHealth()`'s
248
+ // return value, sent verbatim.
249
+ const MemoryHealthSchema = z.object({
250
+ sqliteVec: z.object({
251
+ extensionLoaded: z.boolean(),
252
+ tableExists: z.boolean(),
253
+ initialized: z.boolean(),
254
+ vectorDimensions: z.number(),
255
+ distanceMetric: z.literal("cosine"),
256
+ schema: z.string().nullable(),
257
+ lastPopulate: MemoryVecPopulateStatsSchema.nullable(),
258
+ }),
259
+ counts: z.object({
260
+ total: z.number(),
261
+ withEmbedding: z.number(),
262
+ validEmbedding: z.number(),
263
+ invalidEmbedding: z.number(),
264
+ searchable: z.number(),
265
+ memoryVec: z.number(),
266
+ missingFromVec: z.number(),
267
+ extraInVec: z.number(),
268
+ }),
269
+ retrievalMode: z.enum(["vec", "fallback"]),
270
+ reasons: z.array(z.string()),
271
+ });
272
+
158
273
  const memoryHealth = route({
159
274
  method: "get",
160
275
  path: "/api/memory/health",
@@ -163,13 +278,57 @@ const memoryHealth = route({
163
278
  tags: ["Memory"],
164
279
  auth: { apiKey: true },
165
280
  responses: {
166
- 200: { description: "Memory vector index health" },
281
+ 200: { description: "Memory vector index health", schema: MemoryHealthSchema },
167
282
  },
168
283
  });
169
284
 
170
285
  // Windowed usefulness analytics — sibling of the cheap /health probe.
171
286
  // Reads memory_retrieval + memory_rating + agent_memory posteriors; plan:
172
287
  // thoughts/taras/plans/2026-07-02-memory-retrieval-v2-graph-and-measurement.md Phase 1.
288
+ // Mirrors `UsefulnessStats` and its nested shapes (src/be/memory/usefulness-stats.ts)
289
+ // — `getUsefulnessStats()`'s return value, sent verbatim.
290
+ const UsefulnessStatsSchema = z.object({
291
+ windowDays: z.number(),
292
+ threshold: z.number(),
293
+ cutoff: z.string(),
294
+ volume: z.object({
295
+ retrievals: z.number(),
296
+ distinctMemories: z.number(),
297
+ retrievalGroups: z.number(),
298
+ byEventType: z.object({ search: z.number(), get: z.number() }),
299
+ }),
300
+ byArm: z.array(
301
+ z.object({
302
+ retrievalSource: z.string().nullable(),
303
+ retrievals: z.number(),
304
+ distinctMemories: z.number(),
305
+ citedRetrievals: z.number(),
306
+ citationRate: z.number(),
307
+ }),
308
+ ),
309
+ citationBySource: z.array(
310
+ z.object({
311
+ source: z.string(),
312
+ ratings: z.number(),
313
+ positive: z.number(),
314
+ citationRate: z.number(),
315
+ avgSignal: z.number(),
316
+ }),
317
+ ),
318
+ posterior: z.object({
319
+ totalMemories: z.number(),
320
+ movedFromPrior: z.number(),
321
+ avgPosteriorMean: z.number().nullable(),
322
+ avgPosteriorMeanMoved: z.number().nullable(),
323
+ aboveThreshold: z.number(),
324
+ }),
325
+ sanity: z.object({
326
+ totalRetrievalRows: z.number(),
327
+ totalRatingRows: z.number(),
328
+ ratingsBySource: z.array(z.object({ source: z.string(), count: z.number() })),
329
+ }),
330
+ });
331
+
173
332
  const memoryUsefulness = route({
174
333
  method: "get",
175
334
  path: "/api/memory/usefulness",
@@ -194,7 +353,7 @@ const memoryUsefulness = route({
194
353
  .describe("Posterior-mean threshold for the aboveThreshold count (default 0.6)"),
195
354
  }),
196
355
  responses: {
197
- 200: { description: "Usefulness stats for the window" },
356
+ 200: { description: "Usefulness stats for the window", schema: UsefulnessStatsSchema },
198
357
  400: { description: "Validation error" },
199
358
  },
200
359
  });
@@ -208,11 +367,53 @@ const deleteMemoryById = route({
208
367
  auth: { apiKey: true },
209
368
  params: z.object({ id: z.string().uuid() }),
210
369
  responses: {
211
- 200: { description: "Memory deleted" },
370
+ 200: { description: "Memory deleted", schema: z.object({ deleted: z.boolean() }) },
212
371
  404: { description: "Memory not found" },
213
372
  },
214
373
  });
215
374
 
375
+ // Mirrors `LinkType` / `TargetKind` (src/be/memory/link-resolver.ts).
376
+ const LinkTypeSchema = z.enum([
377
+ "wikilink",
378
+ "sequel",
379
+ "agent-fs-file",
380
+ "agent-ui",
381
+ "pr",
382
+ "external-source",
383
+ ]);
384
+ const TargetKindSchema = z.enum(["memory", "agent-fs-file", "agent-ui", "pr", "external-source"]);
385
+
386
+ // Mirrors `LinkedMemoryRef` (src/be/memory/links-store.ts).
387
+ const LinkedMemoryRefSchema = z.object({
388
+ id: z.string(),
389
+ name: z.string(),
390
+ scope: z.string(),
391
+ });
392
+
393
+ // Mirrors `MemoryLinkView` (src/be/memory/links-store.ts).
394
+ const MemoryLinkViewSchema = z.object({
395
+ id: z.string(),
396
+ linkType: LinkTypeSchema,
397
+ targetKind: TargetKindSchema,
398
+ targetId: z.string(),
399
+ strength: z.number(),
400
+ resolver: z.string(),
401
+ sourceText: z.string().nullable(),
402
+ createdAt: z.string(),
403
+ resolved: z.boolean(),
404
+ target: LinkedMemoryRefSchema.optional(),
405
+ });
406
+
407
+ // Mirrors `MemoryBacklinkView` (src/be/memory/links-store.ts).
408
+ const MemoryBacklinkViewSchema = z.object({
409
+ id: z.string(),
410
+ linkType: LinkTypeSchema,
411
+ strength: z.number(),
412
+ sourceText: z.string().nullable(),
413
+ createdAt: z.string(),
414
+ from: LinkedMemoryRefSchema,
415
+ });
416
+
216
417
  const getMemoryById = route({
217
418
  method: "get",
218
419
  path: "/api/memory/{id}",
@@ -234,6 +435,11 @@ const getMemoryById = route({
234
435
  200: {
235
436
  description:
236
437
  "Memory details, plus `links` (outgoing memory_link rows; memory-kind targets carry `resolved` + ACL-filtered `target` metadata) and `backlinks` (inbound links from other memories, ACL-filtered)",
438
+ schema: z.object({
439
+ memory: AgentMemorySchema,
440
+ links: z.array(MemoryLinkViewSchema),
441
+ backlinks: z.array(MemoryBacklinkViewSchema),
442
+ }),
237
443
  },
238
444
  404: { description: "Memory not found" },
239
445
  },
@@ -291,12 +497,31 @@ const rateMemory = route({
291
497
  events: z.array(RateEventSchema).min(1).max(50),
292
498
  }),
293
499
  responses: {
294
- 200: { description: "Ratings applied; per-event rejections returned in body" },
500
+ 200: {
501
+ description: "Ratings applied; per-event rejections returned in body",
502
+ schema: z.object({
503
+ applied: z.number(),
504
+ rejected: z.array(z.object({ memoryId: z.string(), reason: z.string() })),
505
+ }),
506
+ },
295
507
  400: { description: "Validation error or explicit-self R6 spam-guard rejection" },
296
508
  409: { description: "Duplicate explicit-self rating for (taskId, memoryId)" },
297
509
  },
298
510
  });
299
511
 
512
+ // Mirrors `RetrievalListRow` (src/be/memory/retrieval-store.ts).
513
+ const RetrievalListRowSchema = z.object({
514
+ id: z.string(),
515
+ name: z.string(),
516
+ content: z.string(),
517
+ scope: z.string(),
518
+ source: z.string(),
519
+ scheduleId: z.string().nullable(),
520
+ similarity: z.number().nullable(),
521
+ retrievalSource: z.string().nullable(),
522
+ retrievedAt: z.string(),
523
+ });
524
+
300
525
  const getRetrievals = route({
301
526
  method: "get",
302
527
  path: "/api/memory/retrievals",
@@ -313,7 +538,10 @@ const getRetrievals = route({
313
538
  message: "taskId or sessionId required",
314
539
  }),
315
540
  responses: {
316
- 200: { description: "Retrieval rows joined with agent_memory" },
541
+ 200: {
542
+ description: "Retrieval rows joined with agent_memory",
543
+ schema: z.object({ results: z.array(RetrievalListRowSchema) }),
544
+ },
317
545
  400: { description: "Missing taskId/sessionId or X-Agent-ID" },
318
546
  },
319
547
  });
@@ -322,6 +550,16 @@ const getRetrievals = route({
322
550
  // homepage demo ("this memory references PR #377"). Auth by X-Agent-ID +
323
551
  // Bearer with defence-in-depth: the joined `agent_memory` row must either
324
552
  // be swarm-scope or owned by the requesting agent. Plan §7.
553
+ // Mirrors `MemoryEdgeRow` (src/be/memory/edges-store.ts).
554
+ const MemoryEdgeRowSchema = z.object({
555
+ to: z.string(),
556
+ type: z.literal("references-source"),
557
+ alpha: z.number(),
558
+ beta: z.number(),
559
+ usefulness: z.number(),
560
+ createdAt: z.string(),
561
+ });
562
+
325
563
  const getMemoryEdges = route({
326
564
  method: "get",
327
565
  path: "/api/memory/edges",
@@ -333,7 +571,10 @@ const getMemoryEdges = route({
333
571
  memoryId: z.string().min(1),
334
572
  }),
335
573
  responses: {
336
- 200: { description: "Edges with computed usefulness scores" },
574
+ 200: {
575
+ description: "Edges with computed usefulness scores",
576
+ schema: z.object({ edges: z.array(MemoryEdgeRowSchema) }),
577
+ },
337
578
  400: { description: "Missing memoryId or X-Agent-ID" },
338
579
  },
339
580
  });
@@ -367,7 +608,11 @@ export async function handleMemory(
367
608
  if (source === "session_summary" && sourceTaskId) {
368
609
  const sourceTask = getTaskById(sourceTaskId);
369
610
  if (sourceTask && !shouldPersistAutomaticTaskMemory(sourceTask, persistMemory)) {
370
- json(res, { queued: false, memoryIds: [], skipped: "automatic_task_memory_disabled" }, 202);
611
+ indexMemory.respond(res, 202, {
612
+ queued: false,
613
+ memoryIds: [],
614
+ skipped: "automatic_task_memory_disabled",
615
+ });
371
616
  return true;
372
617
  }
373
618
  }
@@ -414,7 +659,11 @@ export async function handleMemory(
414
659
  (err as Error).message,
415
660
  );
416
661
  }
417
- json(res, { queued: false, memoryIds: [result.memory.id], edited: result.changed }, 202);
662
+ indexMemory.respond(res, 202, {
663
+ queued: false,
664
+ memoryIds: [result.memory.id],
665
+ edited: result.changed,
666
+ });
418
667
  return true;
419
668
  }
420
669
  }
@@ -478,7 +727,7 @@ export async function handleMemory(
478
727
  }
479
728
  })();
480
729
 
481
- json(res, { queued: true, memoryIds: memories.map((m) => m.id) }, 202);
730
+ indexMemory.respond(res, 202, { queued: true, memoryIds: memories.map((m) => m.id) });
482
731
  return true;
483
732
  }
484
733
 
@@ -544,7 +793,7 @@ export async function handleMemory(
544
793
  }
545
794
  }
546
795
 
547
- json(res, {
796
+ searchMemory.respond(res, 200, {
548
797
  results: ranked.map((r) => ({
549
798
  id: r.id,
550
799
  name: r.name,
@@ -560,7 +809,7 @@ export async function handleMemory(
560
809
  });
561
810
  } catch (err) {
562
811
  console.error("[memory-search] Error:", (err as Error).message);
563
- json(res, { results: [] });
812
+ searchMemory.respond(res, 200, { results: [] });
564
813
  }
565
814
  return true;
566
815
  }
@@ -601,7 +850,7 @@ export async function handleMemory(
601
850
  const ranked = rerank(candidates, { limit: candidates.length });
602
851
  const page = ranked.slice(offset, offset + pageLimit);
603
852
 
604
- json(res, {
853
+ listMemory.respond(res, 200, {
605
854
  results: page.map((r) => ({
606
855
  id: r.id,
607
856
  name: r.name,
@@ -644,7 +893,7 @@ export async function handleMemory(
644
893
  const rows = store.list(agentId ?? "", listOptions);
645
894
  const total = store.count(agentId ?? "", listOptions);
646
895
 
647
- json(res, {
896
+ listMemory.respond(res, 200, {
648
897
  results: rows.map((r) => ({
649
898
  id: r.id,
650
899
  name: r.name,
@@ -720,7 +969,7 @@ export async function handleMemory(
720
969
  );
721
970
  }
722
971
  }
723
- json(res, result);
972
+ editMemory.respond(res, 200, result);
724
973
  } catch (err) {
725
974
  const message = (err as Error).message;
726
975
  if (message.includes("not found")) jsonError(res, message, 404);
@@ -734,7 +983,7 @@ export async function handleMemory(
734
983
  const parsed = await memoryHealth.parse(req, res, pathSegments, new URLSearchParams());
735
984
  if (!parsed) return true;
736
985
 
737
- json(res, getMemoryStore().getHealth());
986
+ memoryHealth.respond(res, 200, getMemoryStore().getHealth());
738
987
  return true;
739
988
  }
740
989
 
@@ -744,7 +993,7 @@ export async function handleMemory(
744
993
  if (!parsed) return true;
745
994
 
746
995
  const { days, threshold } = parsed.query;
747
- json(res, getUsefulnessStats({ days, threshold }));
996
+ memoryUsefulness.respond(res, 200, getUsefulnessStats({ days, threshold }));
748
997
  return true;
749
998
  }
750
999
 
@@ -758,7 +1007,7 @@ export async function handleMemory(
758
1007
  jsonError(res, "Memory not found", 404);
759
1008
  return true;
760
1009
  }
761
- json(res, { deleted: true });
1010
+ deleteMemoryById.respond(res, 200, { deleted: true });
762
1011
  return true;
763
1012
  }
764
1013
 
@@ -771,7 +1020,7 @@ export async function handleMemory(
771
1020
  const provider = getEmbeddingProvider();
772
1021
  const memories = store.listForReembedding(agentId ? { agentId } : undefined);
773
1022
 
774
- json(res, { started: true, totalMemories: memories.length }, 202);
1023
+ reEmbedMemory.respond(res, 202, { started: true, totalMemories: memories.length });
775
1024
 
776
1025
  // Async re-embed in batches
777
1026
  (async () => {
@@ -865,7 +1114,7 @@ export async function handleMemory(
865
1114
  throw err;
866
1115
  }
867
1116
 
868
- json(res, { applied, rejected });
1117
+ rateMemory.respond(res, 200, { applied, rejected });
869
1118
  return true;
870
1119
  }
871
1120
 
@@ -881,7 +1130,7 @@ export async function handleMemory(
881
1130
 
882
1131
  const { taskId, sessionId } = parsed.query;
883
1132
  const rows = getRetrievalsForAgent(myAgentId, { taskId, sessionId });
884
- json(res, { results: rows });
1133
+ getRetrievals.respond(res, 200, { results: rows });
885
1134
  return true;
886
1135
  }
887
1136
 
@@ -897,7 +1146,7 @@ export async function handleMemory(
897
1146
 
898
1147
  const { memoryId } = parsed.query;
899
1148
  const edges = listEdgesForAgent(myAgentId, memoryId);
900
- json(res, { edges });
1149
+ getMemoryEdges.respond(res, 200, { edges });
901
1150
  return true;
902
1151
  }
903
1152
 
@@ -951,7 +1200,11 @@ export async function handleMemory(
951
1200
  console.error("[memory-get] link traversal failed:", (err as Error).message);
952
1201
  }
953
1202
 
954
- json(res, { memory, links: linkBlocks.links, backlinks: linkBlocks.backlinks });
1203
+ getMemoryById.respond(res, 200, {
1204
+ memory,
1205
+ links: linkBlocks.links,
1206
+ backlinks: linkBlocks.backlinks,
1207
+ });
955
1208
  return true;
956
1209
  }
957
1210