@props-labs/mesh-os 0.1.7
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/LICENSE +201 -0
- package/README.md +258 -0
- package/dist/core/client.d.ts +142 -0
- package/dist/core/client.js +581 -0
- package/dist/core/taxonomy.d.ts +219 -0
- package/dist/core/taxonomy.js +131 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +20 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +146 -0
- package/package.json +54 -0
- package/src/templates/.env.example +18 -0
- package/src/templates/docker-compose.yml +55 -0
- package/src/templates/hasura/config.yaml +9 -0
- package/src/templates/hasura/metadata/config.yaml +1 -0
- package/src/templates/hasura/metadata/databases/databases.yaml +15 -0
- package/src/templates/hasura/metadata/databases/default/tables/public_agents.yaml +14 -0
- package/src/templates/hasura/metadata/databases/default/tables/public_memories.yaml +17 -0
- package/src/templates/hasura/metadata/databases/default/tables/public_memory_edges.yaml +57 -0
- package/src/templates/hasura/metadata/databases/default/tables/tables.yaml +54 -0
- package/src/templates/hasura/metadata/databases/default/tables/track_tables.yaml +14 -0
- package/src/templates/hasura/metadata/metadata.json +80 -0
- package/src/templates/hasura/metadata/version.yaml +1 -0
- package/src/templates/hasura/migrations/default/1_init/down.sql +13 -0
- package/src/templates/hasura/migrations/default/1_init/up.sql +218 -0
@@ -0,0 +1,581 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.MeshOS = exports.InvalidSlugError = exports.GraphQLError = void 0;
|
7
|
+
/**
|
8
|
+
* Core functionality for MeshOS.
|
9
|
+
*/
|
10
|
+
const openai_1 = __importDefault(require("openai"));
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
12
|
+
const boxen_1 = __importDefault(require("boxen"));
|
13
|
+
const taxonomy_1 = require("./taxonomy");
|
14
|
+
// Constants
|
15
|
+
const MIN_THRESHOLD = 0.3;
|
16
|
+
const SLUG_PATTERN = /^[a-z][a-z0-9_-]*[a-z0-9]$/;
|
17
|
+
/**
|
18
|
+
* GraphQL error class.
|
19
|
+
*/
|
20
|
+
class GraphQLError extends Error {
|
21
|
+
constructor(message) {
|
22
|
+
super(message);
|
23
|
+
this.name = 'GraphQLError';
|
24
|
+
}
|
25
|
+
}
|
26
|
+
exports.GraphQLError = GraphQLError;
|
27
|
+
/**
|
28
|
+
* Invalid slug error class.
|
29
|
+
*/
|
30
|
+
class InvalidSlugError extends Error {
|
31
|
+
constructor(message) {
|
32
|
+
super(message);
|
33
|
+
this.name = 'InvalidSlugError';
|
34
|
+
}
|
35
|
+
}
|
36
|
+
exports.InvalidSlugError = InvalidSlugError;
|
37
|
+
/**
|
38
|
+
* MeshOS client for interacting with the system.
|
39
|
+
*/
|
40
|
+
class MeshOS {
|
41
|
+
constructor(config = {}) {
|
42
|
+
this.url = `${config.url || 'http://localhost:8080'}/v1/graphql`;
|
43
|
+
this.headers = {
|
44
|
+
'Content-Type': 'application/json',
|
45
|
+
'x-hasura-admin-secret': config.apiKey || 'meshos'
|
46
|
+
};
|
47
|
+
// Set up OpenAI
|
48
|
+
const openaiApiKey = config.openaiApiKey || process.env.OPENAI_API_KEY;
|
49
|
+
if (!openaiApiKey) {
|
50
|
+
const boxOptions = {
|
51
|
+
title: 'Missing API Key',
|
52
|
+
titleAlignment: 'center',
|
53
|
+
padding: 1,
|
54
|
+
borderColor: 'yellow',
|
55
|
+
borderStyle: 'round'
|
56
|
+
};
|
57
|
+
console.error((0, boxen_1.default)(chalk_1.default.yellow('⚠️ OpenAI API key not found!\n\n') +
|
58
|
+
'Please set your OpenAI API key in the environment:\n' +
|
59
|
+
chalk_1.default.green('OPENAI_API_KEY=your-key-here') + '\n\n' +
|
60
|
+
'You can get an API key at: ' + chalk_1.default.blue('https://platform.openai.com/api-keys'), boxOptions));
|
61
|
+
throw new Error('OpenAI API key is required');
|
62
|
+
}
|
63
|
+
this.openai = new openai_1.default({ apiKey: openaiApiKey });
|
64
|
+
}
|
65
|
+
validateSlug(slug) {
|
66
|
+
return SLUG_PATTERN.test(slug);
|
67
|
+
}
|
68
|
+
/**
|
69
|
+
* Execute a GraphQL query.
|
70
|
+
*/
|
71
|
+
async executeQuery(query, variables) {
|
72
|
+
const response = await fetch(this.url, {
|
73
|
+
method: 'POST',
|
74
|
+
headers: this.headers,
|
75
|
+
body: JSON.stringify({
|
76
|
+
query,
|
77
|
+
variables: variables || {}
|
78
|
+
})
|
79
|
+
});
|
80
|
+
if (!response.ok) {
|
81
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
82
|
+
}
|
83
|
+
const result = await response.json();
|
84
|
+
if (result.errors) {
|
85
|
+
throw new GraphQLError(result.errors[0].message);
|
86
|
+
}
|
87
|
+
return result.data;
|
88
|
+
}
|
89
|
+
/**
|
90
|
+
* Create an embedding for the given text.
|
91
|
+
*/
|
92
|
+
async createEmbedding(text) {
|
93
|
+
const response = await this.openai.embeddings.create({
|
94
|
+
model: 'text-embedding-3-small',
|
95
|
+
input: text
|
96
|
+
});
|
97
|
+
return response.data[0].embedding;
|
98
|
+
}
|
99
|
+
/**
|
100
|
+
* Register a new agent in the system.
|
101
|
+
*/
|
102
|
+
async registerAgent(name, description, metadata, slug) {
|
103
|
+
if (slug && !this.validateSlug(slug)) {
|
104
|
+
throw new InvalidSlugError("Slug must start with a letter and contain only lowercase letters, " +
|
105
|
+
"numbers, hyphens, and underscores");
|
106
|
+
}
|
107
|
+
// First check if agent with slug exists
|
108
|
+
if (slug) {
|
109
|
+
const existing = await this.getAgentBySlug(slug);
|
110
|
+
if (existing) {
|
111
|
+
return existing;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
const query = `
|
115
|
+
mutation RegisterAgent($name: String!, $description: String!, $metadata: jsonb, $slug: String) {
|
116
|
+
insert_agents_one(object: {
|
117
|
+
name: $name,
|
118
|
+
description: $description,
|
119
|
+
metadata: $metadata,
|
120
|
+
status: "active",
|
121
|
+
slug: $slug
|
122
|
+
}) {
|
123
|
+
id
|
124
|
+
name
|
125
|
+
description
|
126
|
+
metadata
|
127
|
+
status
|
128
|
+
slug
|
129
|
+
}
|
130
|
+
}
|
131
|
+
`;
|
132
|
+
const result = await this.executeQuery(query, {
|
133
|
+
name,
|
134
|
+
description,
|
135
|
+
metadata: metadata || {},
|
136
|
+
slug
|
137
|
+
});
|
138
|
+
return result.insert_agents_one;
|
139
|
+
}
|
140
|
+
/**
|
141
|
+
* Get agent details by slug.
|
142
|
+
*/
|
143
|
+
async getAgentBySlug(slug) {
|
144
|
+
if (!this.validateSlug(slug)) {
|
145
|
+
throw new InvalidSlugError("Slug must start with a letter and contain only lowercase letters, " +
|
146
|
+
"numbers, hyphens, and underscores");
|
147
|
+
}
|
148
|
+
const query = `
|
149
|
+
query GetAgentBySlug($slug: String!) {
|
150
|
+
agents(where: {slug: {_eq: $slug}}, limit: 1) {
|
151
|
+
id
|
152
|
+
name
|
153
|
+
description
|
154
|
+
metadata
|
155
|
+
status
|
156
|
+
slug
|
157
|
+
}
|
158
|
+
}
|
159
|
+
`;
|
160
|
+
const result = await this.executeQuery(query, { slug });
|
161
|
+
return result.agents[0] || null;
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* Unregister an agent and remove all their memories.
|
165
|
+
*/
|
166
|
+
async unregisterAgent(agentId) {
|
167
|
+
const query = `
|
168
|
+
mutation UnregisterAgent($id: uuid!) {
|
169
|
+
delete_agents_by_pk(id: $id) {
|
170
|
+
id
|
171
|
+
}
|
172
|
+
}
|
173
|
+
`;
|
174
|
+
const result = await this.executeQuery(query, {
|
175
|
+
id: agentId
|
176
|
+
});
|
177
|
+
return result.delete_agents_by_pk !== null;
|
178
|
+
}
|
179
|
+
/**
|
180
|
+
* Get agent details by ID.
|
181
|
+
*/
|
182
|
+
async getAgent(agentId) {
|
183
|
+
const query = `
|
184
|
+
query GetAgent($id: uuid!) {
|
185
|
+
agents_by_pk(id: $id) {
|
186
|
+
id
|
187
|
+
name
|
188
|
+
description
|
189
|
+
metadata
|
190
|
+
status
|
191
|
+
slug
|
192
|
+
}
|
193
|
+
}
|
194
|
+
`;
|
195
|
+
const result = await this.executeQuery(query, {
|
196
|
+
id: agentId
|
197
|
+
});
|
198
|
+
return result.agents_by_pk;
|
199
|
+
}
|
200
|
+
/**
|
201
|
+
* Store a new memory.
|
202
|
+
*/
|
203
|
+
async remember(content, agentId, metadata) {
|
204
|
+
// Create default metadata if none provided
|
205
|
+
const fullMetadata = taxonomy_1.memoryMetadataSchema.parse({
|
206
|
+
type: taxonomy_1.DataType.KNOWLEDGE,
|
207
|
+
subtype: taxonomy_1.KnowledgeSubtype.DATASET,
|
208
|
+
tags: [],
|
209
|
+
version: 1,
|
210
|
+
history: [],
|
211
|
+
additional: {},
|
212
|
+
...metadata
|
213
|
+
});
|
214
|
+
// Create embedding
|
215
|
+
const embedding = await this.createEmbedding(content);
|
216
|
+
const embeddingStr = `[${embedding.join(',')}]`;
|
217
|
+
const query = `
|
218
|
+
mutation Remember($content: String!, $agentId: uuid!, $metadata: jsonb!, $embedding: vector!) {
|
219
|
+
insert_memories_one(object: {
|
220
|
+
content: $content,
|
221
|
+
agent_id: $agentId,
|
222
|
+
metadata: $metadata,
|
223
|
+
embedding: $embedding
|
224
|
+
}) {
|
225
|
+
id
|
226
|
+
agent_id
|
227
|
+
content
|
228
|
+
metadata
|
229
|
+
embedding
|
230
|
+
created_at
|
231
|
+
updated_at
|
232
|
+
}
|
233
|
+
}
|
234
|
+
`;
|
235
|
+
const result = await this.executeQuery(query, {
|
236
|
+
content,
|
237
|
+
agentId,
|
238
|
+
metadata: fullMetadata,
|
239
|
+
embedding: embeddingStr
|
240
|
+
});
|
241
|
+
// Convert snake_case to camelCase
|
242
|
+
const { agent_id, created_at, updated_at, ...rest } = result.insert_memories_one;
|
243
|
+
return {
|
244
|
+
...rest,
|
245
|
+
agentId: agent_id,
|
246
|
+
createdAt: created_at,
|
247
|
+
updatedAt: updated_at,
|
248
|
+
};
|
249
|
+
}
|
250
|
+
/**
|
251
|
+
* Delete a specific memory.
|
252
|
+
*/
|
253
|
+
async forget(memoryId) {
|
254
|
+
const query = `
|
255
|
+
mutation Forget($id: uuid!) {
|
256
|
+
delete_memories_by_pk(id: $id) {
|
257
|
+
id
|
258
|
+
}
|
259
|
+
}
|
260
|
+
`;
|
261
|
+
const result = await this.executeQuery(query, {
|
262
|
+
id: memoryId
|
263
|
+
});
|
264
|
+
return result.delete_memories_by_pk !== null;
|
265
|
+
}
|
266
|
+
/**
|
267
|
+
* Create a link between two memories.
|
268
|
+
*/
|
269
|
+
async linkMemories(sourceMemoryId, targetMemoryId, relationship, weight = 1.0, metadata) {
|
270
|
+
const query = `
|
271
|
+
mutation LinkMemories(
|
272
|
+
$sourceMemory: uuid!,
|
273
|
+
$targetMemory: uuid!,
|
274
|
+
$relationship: String!,
|
275
|
+
$weight: float8!,
|
276
|
+
$metadata: jsonb!
|
277
|
+
) {
|
278
|
+
insert_memory_edges_one(object: {
|
279
|
+
source_memory: $sourceMemory,
|
280
|
+
target_memory: $targetMemory,
|
281
|
+
relationship: $relationship,
|
282
|
+
weight: $weight,
|
283
|
+
metadata: $metadata
|
284
|
+
}) {
|
285
|
+
id
|
286
|
+
source_memory
|
287
|
+
target_memory
|
288
|
+
relationship
|
289
|
+
weight
|
290
|
+
created_at
|
291
|
+
metadata
|
292
|
+
}
|
293
|
+
}
|
294
|
+
`;
|
295
|
+
const fullMetadata = {
|
296
|
+
relationship,
|
297
|
+
weight,
|
298
|
+
bidirectional: false,
|
299
|
+
additional: {},
|
300
|
+
...metadata
|
301
|
+
};
|
302
|
+
const result = await this.executeQuery(query, {
|
303
|
+
sourceMemory: sourceMemoryId,
|
304
|
+
targetMemory: targetMemoryId,
|
305
|
+
relationship,
|
306
|
+
weight,
|
307
|
+
metadata: fullMetadata
|
308
|
+
});
|
309
|
+
// Convert snake_case to camelCase
|
310
|
+
const { source_memory, target_memory, created_at, ...rest } = result.insert_memory_edges_one;
|
311
|
+
return {
|
312
|
+
...rest,
|
313
|
+
sourceMemory: source_memory,
|
314
|
+
targetMemory: target_memory,
|
315
|
+
createdAt: created_at,
|
316
|
+
};
|
317
|
+
}
|
318
|
+
/**
|
319
|
+
* Remove links between two memories.
|
320
|
+
*/
|
321
|
+
async unlinkMemories(sourceMemoryId, targetMemoryId, relationship) {
|
322
|
+
const conditions = {
|
323
|
+
source_memory: { _eq: sourceMemoryId },
|
324
|
+
target_memory: { _eq: targetMemoryId }
|
325
|
+
};
|
326
|
+
if (relationship) {
|
327
|
+
conditions.relationship = { _eq: relationship };
|
328
|
+
}
|
329
|
+
const query = `
|
330
|
+
mutation UnlinkMemories($where: memory_edges_bool_exp!) {
|
331
|
+
delete_memory_edges(where: $where) {
|
332
|
+
affected_rows
|
333
|
+
}
|
334
|
+
}
|
335
|
+
`;
|
336
|
+
const result = await this.executeQuery(query, {
|
337
|
+
where: conditions
|
338
|
+
});
|
339
|
+
return result.delete_memory_edges.affected_rows > 0;
|
340
|
+
}
|
341
|
+
/**
|
342
|
+
* Update a memory and optionally create a version edge to the previous version.
|
343
|
+
*/
|
344
|
+
async updateMemory(memoryId, content, metadata, createVersionEdge = true) {
|
345
|
+
// First get the current memory
|
346
|
+
const query = `
|
347
|
+
query GetMemory($id: uuid!) {
|
348
|
+
memories_by_pk(id: $id) {
|
349
|
+
id
|
350
|
+
agent_id
|
351
|
+
content
|
352
|
+
metadata
|
353
|
+
embedding
|
354
|
+
created_at
|
355
|
+
updated_at
|
356
|
+
}
|
357
|
+
}
|
358
|
+
`;
|
359
|
+
const result = await this.executeQuery(query, {
|
360
|
+
id: memoryId
|
361
|
+
});
|
362
|
+
const oldMemory = result.memories_by_pk;
|
363
|
+
if (!oldMemory) {
|
364
|
+
throw new Error(`Memory ${memoryId} not found`);
|
365
|
+
}
|
366
|
+
// Create new memory with updated content and metadata
|
367
|
+
const newMemory = await this.remember(content, oldMemory.agent_id, {
|
368
|
+
...oldMemory.metadata,
|
369
|
+
version: oldMemory.metadata.version + 1,
|
370
|
+
previousVersion: oldMemory.id,
|
371
|
+
...metadata
|
372
|
+
});
|
373
|
+
// Create version edge if requested
|
374
|
+
if (createVersionEdge) {
|
375
|
+
await this.linkMemories(oldMemory.id, newMemory.id, taxonomy_1.EdgeType.VERSION_OF, 1.0, {
|
376
|
+
relationship: taxonomy_1.EdgeType.VERSION_OF,
|
377
|
+
weight: 1.0,
|
378
|
+
bidirectional: false,
|
379
|
+
additional: { version_increment: 1 }
|
380
|
+
});
|
381
|
+
}
|
382
|
+
return newMemory;
|
383
|
+
}
|
384
|
+
/**
|
385
|
+
* Get memories connected to the given memory.
|
386
|
+
*/
|
387
|
+
async getConnectedMemories(memoryId, relationship, maxDepth = 1) {
|
388
|
+
const query = `
|
389
|
+
query GetConnectedMemories(
|
390
|
+
$memoryId: uuid!,
|
391
|
+
$relationship: String,
|
392
|
+
$maxDepth: Int!
|
393
|
+
) {
|
394
|
+
get_connected_memories(
|
395
|
+
memory_id: $memoryId,
|
396
|
+
relationship_type: $relationship,
|
397
|
+
max_depth: $maxDepth
|
398
|
+
) {
|
399
|
+
source_id
|
400
|
+
target_id
|
401
|
+
relationship
|
402
|
+
weight
|
403
|
+
depth
|
404
|
+
}
|
405
|
+
}
|
406
|
+
`;
|
407
|
+
const result = await this.executeQuery(query, {
|
408
|
+
memoryId,
|
409
|
+
relationship,
|
410
|
+
maxDepth
|
411
|
+
});
|
412
|
+
return result.get_connected_memories;
|
413
|
+
}
|
414
|
+
/**
|
415
|
+
* Generate semantic variations of the query.
|
416
|
+
*/
|
417
|
+
async expandQuery(query, numVariations = 2) {
|
418
|
+
const systemPrompt = `Generate ${numVariations} semantic variations of the query that mean the same thing.\n` +
|
419
|
+
'Focus on different ways to express the same concept.\n' +
|
420
|
+
'Return ONLY the variations, one per line, no numbering or extra text.\n' +
|
421
|
+
'Variations should be concise and natural, similar in length to the original.';
|
422
|
+
const response = await this.openai.chat.completions.create({
|
423
|
+
model: 'gpt-3.5-turbo',
|
424
|
+
messages: [{
|
425
|
+
role: 'system',
|
426
|
+
content: systemPrompt
|
427
|
+
}, {
|
428
|
+
role: 'user',
|
429
|
+
content: query
|
430
|
+
}],
|
431
|
+
temperature: 0.7
|
432
|
+
});
|
433
|
+
const content = response.choices[0]?.message?.content;
|
434
|
+
if (!content) {
|
435
|
+
return [query];
|
436
|
+
}
|
437
|
+
const result = [query]; // Include original
|
438
|
+
result.push(...content
|
439
|
+
.split('\n')
|
440
|
+
.map(v => v.trim())
|
441
|
+
.filter(Boolean));
|
442
|
+
return result.slice(0, numVariations + 1);
|
443
|
+
}
|
444
|
+
/**
|
445
|
+
* Search memories by semantic similarity.
|
446
|
+
*/
|
447
|
+
async recall(options) {
|
448
|
+
const { query, agentId, limit = 5, threshold = 0.7, minResults = 1, adaptiveThreshold = true, useSemanticExpansion = true, filters } = options;
|
449
|
+
// First try: Direct search with initial threshold
|
450
|
+
let results = await this.recallWithThreshold({
|
451
|
+
query,
|
452
|
+
threshold,
|
453
|
+
agentId,
|
454
|
+
limit,
|
455
|
+
filters
|
456
|
+
});
|
457
|
+
if (results.length >= minResults) {
|
458
|
+
return results.slice(0, limit);
|
459
|
+
}
|
460
|
+
// Second try: Adaptive threshold
|
461
|
+
if (adaptiveThreshold) {
|
462
|
+
let currentThreshold = threshold - 0.05;
|
463
|
+
while (currentThreshold >= MIN_THRESHOLD && results.length < minResults) {
|
464
|
+
const newResults = await this.recallWithThreshold({
|
465
|
+
query,
|
466
|
+
threshold: currentThreshold,
|
467
|
+
agentId,
|
468
|
+
limit,
|
469
|
+
filters
|
470
|
+
});
|
471
|
+
// Add new unique results
|
472
|
+
for (const result of newResults) {
|
473
|
+
if (!results.some(r => r.id === result.id)) {
|
474
|
+
results.push(result);
|
475
|
+
}
|
476
|
+
}
|
477
|
+
if (results.length >= minResults)
|
478
|
+
break;
|
479
|
+
currentThreshold -= 0.05;
|
480
|
+
}
|
481
|
+
}
|
482
|
+
// Third try: Semantic expansion
|
483
|
+
if (results.length === 0 && useSemanticExpansion) {
|
484
|
+
const variations = await this.expandQuery(query);
|
485
|
+
const seenIds = new Map();
|
486
|
+
// Try each variation with original threshold
|
487
|
+
for (const variation of variations.slice(1)) {
|
488
|
+
const variationResults = await this.recallWithThreshold({
|
489
|
+
query: variation,
|
490
|
+
threshold,
|
491
|
+
agentId,
|
492
|
+
limit,
|
493
|
+
filters
|
494
|
+
});
|
495
|
+
for (const memory of variationResults) {
|
496
|
+
const existingMemory = seenIds.get(memory.id);
|
497
|
+
if (!existingMemory || (memory.similarity || 0) > (existingMemory.similarity || 0)) {
|
498
|
+
seenIds.set(memory.id, memory);
|
499
|
+
}
|
500
|
+
}
|
501
|
+
if (seenIds.size >= minResults)
|
502
|
+
break;
|
503
|
+
}
|
504
|
+
// If still no results, try variations with adaptive threshold
|
505
|
+
if (seenIds.size === 0 && adaptiveThreshold) {
|
506
|
+
let currentThreshold = threshold - 0.05;
|
507
|
+
while (currentThreshold >= MIN_THRESHOLD && seenIds.size === 0) {
|
508
|
+
for (const variation of variations.slice(1)) {
|
509
|
+
const variationResults = await this.recallWithThreshold({
|
510
|
+
query: variation,
|
511
|
+
threshold: currentThreshold,
|
512
|
+
agentId,
|
513
|
+
limit,
|
514
|
+
filters
|
515
|
+
});
|
516
|
+
for (const memory of variationResults) {
|
517
|
+
const existingMemory = seenIds.get(memory.id);
|
518
|
+
if (!existingMemory || (memory.similarity || 0) > (existingMemory.similarity || 0)) {
|
519
|
+
seenIds.set(memory.id, memory);
|
520
|
+
}
|
521
|
+
}
|
522
|
+
if (seenIds.size > 0)
|
523
|
+
break;
|
524
|
+
}
|
525
|
+
if (seenIds.size > 0)
|
526
|
+
break;
|
527
|
+
currentThreshold -= 0.05;
|
528
|
+
}
|
529
|
+
}
|
530
|
+
if (seenIds.size > 0) {
|
531
|
+
results = Array.from(seenIds.values());
|
532
|
+
}
|
533
|
+
}
|
534
|
+
// Sort by similarity and return
|
535
|
+
results.sort((a, b) => (b.similarity || 0) - (a.similarity || 0));
|
536
|
+
return results.slice(0, limit);
|
537
|
+
}
|
538
|
+
/**
|
539
|
+
* Internal method to perform recall with a specific threshold.
|
540
|
+
*/
|
541
|
+
async recallWithThreshold(options) {
|
542
|
+
const { query, threshold, agentId, limit = 10, filters } = options;
|
543
|
+
// Create embedding for the query
|
544
|
+
const embedding = await this.createEmbedding(query);
|
545
|
+
const embeddingStr = `[${embedding.join(',')}]`;
|
546
|
+
const gqlQuery = `
|
547
|
+
query SearchMemories($args: search_memories_args!) {
|
548
|
+
search_memories(args: $args) {
|
549
|
+
id
|
550
|
+
agent_id
|
551
|
+
content
|
552
|
+
metadata
|
553
|
+
embedding
|
554
|
+
similarity
|
555
|
+
created_at
|
556
|
+
updated_at
|
557
|
+
}
|
558
|
+
}
|
559
|
+
`;
|
560
|
+
const result = await this.executeQuery(gqlQuery, {
|
561
|
+
args: {
|
562
|
+
query_embedding: embeddingStr,
|
563
|
+
match_threshold: threshold,
|
564
|
+
match_count: limit,
|
565
|
+
filter_agent_id: agentId,
|
566
|
+
...filters
|
567
|
+
}
|
568
|
+
});
|
569
|
+
return result.search_memories.map(memory => ({
|
570
|
+
id: memory.id,
|
571
|
+
agentId: memory.agent_id,
|
572
|
+
content: memory.content,
|
573
|
+
metadata: memory.metadata,
|
574
|
+
embedding: memory.embedding,
|
575
|
+
similarity: memory.similarity,
|
576
|
+
createdAt: memory.created_at,
|
577
|
+
updatedAt: memory.updated_at
|
578
|
+
}));
|
579
|
+
}
|
580
|
+
}
|
581
|
+
exports.MeshOS = MeshOS;
|