@desplega.ai/agent-swarm 1.73.2 → 1.73.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/openapi.json +107 -1
- package/package.json +1 -1
- package/src/http/memory.ts +172 -0
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.73.
|
|
5
|
+
"version": "1.73.3",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -2914,6 +2914,112 @@
|
|
|
2914
2914
|
}
|
|
2915
2915
|
}
|
|
2916
2916
|
},
|
|
2917
|
+
"/api/memory/list": {
|
|
2918
|
+
"post": {
|
|
2919
|
+
"summary": "List or semantically search memories across all agents (debug/admin)",
|
|
2920
|
+
"tags": [
|
|
2921
|
+
"Memory"
|
|
2922
|
+
],
|
|
2923
|
+
"security": [
|
|
2924
|
+
{
|
|
2925
|
+
"bearerAuth": []
|
|
2926
|
+
}
|
|
2927
|
+
],
|
|
2928
|
+
"requestBody": {
|
|
2929
|
+
"content": {
|
|
2930
|
+
"application/json": {
|
|
2931
|
+
"schema": {
|
|
2932
|
+
"type": "object",
|
|
2933
|
+
"properties": {
|
|
2934
|
+
"query": {
|
|
2935
|
+
"type": "string",
|
|
2936
|
+
"description": "Natural-language query. If present, runs semantic search; otherwise lists by recency."
|
|
2937
|
+
},
|
|
2938
|
+
"agentId": {
|
|
2939
|
+
"type": "string",
|
|
2940
|
+
"format": "uuid",
|
|
2941
|
+
"description": "Filter to a single agent. Omit for all."
|
|
2942
|
+
},
|
|
2943
|
+
"scope": {
|
|
2944
|
+
"type": "string",
|
|
2945
|
+
"enum": [
|
|
2946
|
+
"agent",
|
|
2947
|
+
"swarm",
|
|
2948
|
+
"all"
|
|
2949
|
+
],
|
|
2950
|
+
"default": "all"
|
|
2951
|
+
},
|
|
2952
|
+
"source": {
|
|
2953
|
+
"type": "string",
|
|
2954
|
+
"enum": [
|
|
2955
|
+
"manual",
|
|
2956
|
+
"file_index",
|
|
2957
|
+
"session_summary",
|
|
2958
|
+
"task_completion"
|
|
2959
|
+
]
|
|
2960
|
+
},
|
|
2961
|
+
"sourcePath": {
|
|
2962
|
+
"type": "string",
|
|
2963
|
+
"description": "Substring match against sourcePath (case-insensitive). Useful for file_index memories."
|
|
2964
|
+
},
|
|
2965
|
+
"limit": {
|
|
2966
|
+
"type": "integer",
|
|
2967
|
+
"minimum": 1,
|
|
2968
|
+
"maximum": 100,
|
|
2969
|
+
"default": 20
|
|
2970
|
+
},
|
|
2971
|
+
"offset": {
|
|
2972
|
+
"type": "integer",
|
|
2973
|
+
"minimum": 0,
|
|
2974
|
+
"default": 0
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
},
|
|
2981
|
+
"responses": {
|
|
2982
|
+
"200": {
|
|
2983
|
+
"description": "Memory list / search results"
|
|
2984
|
+
},
|
|
2985
|
+
"400": {
|
|
2986
|
+
"description": "Validation error"
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
},
|
|
2991
|
+
"/api/memory/{id}": {
|
|
2992
|
+
"delete": {
|
|
2993
|
+
"summary": "Delete a single memory by ID (debug/admin)",
|
|
2994
|
+
"tags": [
|
|
2995
|
+
"Memory"
|
|
2996
|
+
],
|
|
2997
|
+
"security": [
|
|
2998
|
+
{
|
|
2999
|
+
"bearerAuth": []
|
|
3000
|
+
}
|
|
3001
|
+
],
|
|
3002
|
+
"parameters": [
|
|
3003
|
+
{
|
|
3004
|
+
"schema": {
|
|
3005
|
+
"type": "string",
|
|
3006
|
+
"format": "uuid"
|
|
3007
|
+
},
|
|
3008
|
+
"required": true,
|
|
3009
|
+
"name": "id",
|
|
3010
|
+
"in": "path"
|
|
3011
|
+
}
|
|
3012
|
+
],
|
|
3013
|
+
"responses": {
|
|
3014
|
+
"200": {
|
|
3015
|
+
"description": "Memory deleted"
|
|
3016
|
+
},
|
|
3017
|
+
"404": {
|
|
3018
|
+
"description": "Memory not found"
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
},
|
|
2917
3023
|
"/api/prompt-templates/resolved": {
|
|
2918
3024
|
"get": {
|
|
2919
3025
|
"summary": "Resolve a prompt template for a given event type and scope chain",
|
package/package.json
CHANGED
package/src/http/memory.ts
CHANGED
|
@@ -69,6 +69,52 @@ const reEmbedMemory = route({
|
|
|
69
69
|
},
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
const listMemory = route({
|
|
73
|
+
method: "post",
|
|
74
|
+
path: "/api/memory/list",
|
|
75
|
+
pattern: ["api", "memory", "list"],
|
|
76
|
+
summary: "List or semantically search memories across all agents (debug/admin)",
|
|
77
|
+
tags: ["Memory"],
|
|
78
|
+
auth: { apiKey: true },
|
|
79
|
+
body: z.object({
|
|
80
|
+
query: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe(
|
|
84
|
+
"Natural-language query. If present, runs semantic search; otherwise lists by recency.",
|
|
85
|
+
),
|
|
86
|
+
agentId: z.string().uuid().optional().describe("Filter to a single agent. Omit for all."),
|
|
87
|
+
scope: z.enum(["agent", "swarm", "all"]).default("all"),
|
|
88
|
+
source: AgentMemorySourceSchema.optional(),
|
|
89
|
+
sourcePath: z
|
|
90
|
+
.string()
|
|
91
|
+
.optional()
|
|
92
|
+
.describe(
|
|
93
|
+
"Substring match against sourcePath (case-insensitive). Useful for file_index memories.",
|
|
94
|
+
),
|
|
95
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
96
|
+
offset: z.number().int().min(0).default(0),
|
|
97
|
+
}),
|
|
98
|
+
responses: {
|
|
99
|
+
200: { description: "Memory list / search results" },
|
|
100
|
+
400: { description: "Validation error" },
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const deleteMemoryById = route({
|
|
105
|
+
method: "delete",
|
|
106
|
+
path: "/api/memory/{id}",
|
|
107
|
+
pattern: ["api", "memory", null],
|
|
108
|
+
summary: "Delete a single memory by ID (debug/admin)",
|
|
109
|
+
tags: ["Memory"],
|
|
110
|
+
auth: { apiKey: true },
|
|
111
|
+
params: z.object({ id: z.string().uuid() }),
|
|
112
|
+
responses: {
|
|
113
|
+
200: { description: "Memory deleted" },
|
|
114
|
+
404: { description: "Memory not found" },
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
72
118
|
// ─── Handler ─────────────────────────────────────────────────────────────────
|
|
73
119
|
|
|
74
120
|
export async function handleMemory(
|
|
@@ -182,6 +228,132 @@ export async function handleMemory(
|
|
|
182
228
|
return true;
|
|
183
229
|
}
|
|
184
230
|
|
|
231
|
+
if (listMemory.match(req.method, pathSegments)) {
|
|
232
|
+
const parsed = await listMemory.parse(req, res, pathSegments, new URLSearchParams());
|
|
233
|
+
if (!parsed) return true;
|
|
234
|
+
|
|
235
|
+
const { query, agentId, scope, source, sourcePath, limit, offset } = parsed.body;
|
|
236
|
+
const store = getMemoryStore();
|
|
237
|
+
const pathNeedle = sourcePath?.trim().toLowerCase();
|
|
238
|
+
const matchesPath = (p: string | null) =>
|
|
239
|
+
!pathNeedle || (p?.toLowerCase().includes(pathNeedle) ?? false);
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
if (query && query.trim().length > 0) {
|
|
243
|
+
const provider = getEmbeddingProvider();
|
|
244
|
+
const queryEmbedding = await provider.embed(query.trim());
|
|
245
|
+
|
|
246
|
+
if (!queryEmbedding) {
|
|
247
|
+
json(res, { results: [], total: 0, mode: "semantic" });
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const candidateLimit = Math.min(limit, 100) * CANDIDATE_SET_MULTIPLIER;
|
|
252
|
+
let candidates = store.search(queryEmbedding, agentId ?? "", {
|
|
253
|
+
scope,
|
|
254
|
+
limit: candidateLimit,
|
|
255
|
+
isLead: true,
|
|
256
|
+
source,
|
|
257
|
+
});
|
|
258
|
+
if (agentId) {
|
|
259
|
+
candidates = candidates.filter((c) => c.agentId === agentId);
|
|
260
|
+
}
|
|
261
|
+
if (pathNeedle) {
|
|
262
|
+
candidates = candidates.filter((c) => matchesPath(c.sourcePath));
|
|
263
|
+
}
|
|
264
|
+
const ranked = rerank(candidates, { limit: Math.min(limit, 100) });
|
|
265
|
+
|
|
266
|
+
json(res, {
|
|
267
|
+
results: ranked.map((r) => ({
|
|
268
|
+
id: r.id,
|
|
269
|
+
name: r.name,
|
|
270
|
+
content: r.content,
|
|
271
|
+
agentId: r.agentId,
|
|
272
|
+
scope: r.scope,
|
|
273
|
+
source: r.source,
|
|
274
|
+
similarity: r.similarity,
|
|
275
|
+
createdAt: r.createdAt,
|
|
276
|
+
accessedAt: r.accessedAt,
|
|
277
|
+
accessCount: r.accessCount ?? 0,
|
|
278
|
+
expiresAt: r.expiresAt ?? null,
|
|
279
|
+
embeddingModel: r.embeddingModel ?? null,
|
|
280
|
+
sourceTaskId: r.sourceTaskId,
|
|
281
|
+
sourcePath: r.sourcePath,
|
|
282
|
+
chunkIndex: r.chunkIndex,
|
|
283
|
+
totalChunks: r.totalChunks,
|
|
284
|
+
tags: r.tags,
|
|
285
|
+
})),
|
|
286
|
+
total: ranked.length,
|
|
287
|
+
mode: "semantic",
|
|
288
|
+
});
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// When filtering by sourcePath, over-fetch then post-filter so the visible
|
|
293
|
+
// page isn't gutted by the in-memory filter.
|
|
294
|
+
const fetchLimit = pathNeedle
|
|
295
|
+
? Math.min(500, Math.max(limit * 10, 100))
|
|
296
|
+
: Math.min(limit, 100);
|
|
297
|
+
let rows = store.list(agentId ?? "", {
|
|
298
|
+
scope,
|
|
299
|
+
limit: fetchLimit,
|
|
300
|
+
offset,
|
|
301
|
+
isLead: true,
|
|
302
|
+
});
|
|
303
|
+
if (agentId) {
|
|
304
|
+
rows = rows.filter((r) => r.agentId === agentId);
|
|
305
|
+
}
|
|
306
|
+
if (source) {
|
|
307
|
+
rows = rows.filter((r) => r.source === source);
|
|
308
|
+
}
|
|
309
|
+
if (pathNeedle) {
|
|
310
|
+
rows = rows.filter((r) => matchesPath(r.sourcePath));
|
|
311
|
+
}
|
|
312
|
+
rows = rows.slice(0, Math.min(limit, 100));
|
|
313
|
+
|
|
314
|
+
json(res, {
|
|
315
|
+
results: rows.map((r) => ({
|
|
316
|
+
id: r.id,
|
|
317
|
+
name: r.name,
|
|
318
|
+
content: r.content,
|
|
319
|
+
agentId: r.agentId,
|
|
320
|
+
scope: r.scope,
|
|
321
|
+
source: r.source,
|
|
322
|
+
createdAt: r.createdAt,
|
|
323
|
+
accessedAt: r.accessedAt,
|
|
324
|
+
accessCount: r.accessCount ?? 0,
|
|
325
|
+
expiresAt: r.expiresAt ?? null,
|
|
326
|
+
embeddingModel: r.embeddingModel ?? null,
|
|
327
|
+
sourceTaskId: r.sourceTaskId,
|
|
328
|
+
sourcePath: r.sourcePath,
|
|
329
|
+
chunkIndex: r.chunkIndex,
|
|
330
|
+
totalChunks: r.totalChunks,
|
|
331
|
+
tags: r.tags,
|
|
332
|
+
})),
|
|
333
|
+
total: rows.length,
|
|
334
|
+
mode: "list",
|
|
335
|
+
});
|
|
336
|
+
} catch (err) {
|
|
337
|
+
console.error("[memory-list] Error:", (err as Error).message);
|
|
338
|
+
jsonError(res, "Memory list failed", 500);
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (deleteMemoryById.match(req.method, pathSegments)) {
|
|
344
|
+
const parsed = await deleteMemoryById.parse(req, res, pathSegments, new URLSearchParams());
|
|
345
|
+
if (!parsed) return true;
|
|
346
|
+
|
|
347
|
+
const store = getMemoryStore();
|
|
348
|
+
const deleted = store.delete(parsed.params.id);
|
|
349
|
+
if (!deleted) {
|
|
350
|
+
jsonError(res, "Memory not found", 404);
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
json(res, { deleted: true });
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
|
|
185
357
|
if (reEmbedMemory.match(req.method, pathSegments)) {
|
|
186
358
|
const parsed = await reEmbedMemory.parse(req, res, pathSegments, new URLSearchParams());
|
|
187
359
|
if (!parsed) return true;
|