@props-labs/mesh-os 0.1.9 → 0.1.11

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.
@@ -1,4 +1,4 @@
1
- import { EdgeType, type AgentStatus, type EdgeMetadata, type MemoryMetadata } from './taxonomy';
1
+ import { EdgeType, type AgentStatus, type EdgeMetadata, type MemoryMetadata, type TimestampFilter } from './taxonomy';
2
2
  /**
3
3
  * An agent in the system.
4
4
  */
@@ -21,6 +21,7 @@ export interface Memory {
21
21
  embedding: number[];
22
22
  createdAt: string;
23
23
  updatedAt: string;
24
+ expiresAt?: string;
24
25
  similarity?: number;
25
26
  }
26
27
  /**
@@ -91,7 +92,7 @@ export declare class MeshOS {
91
92
  /**
92
93
  * Store a new memory.
93
94
  */
94
- remember(content: string, agentId: string, metadata?: Partial<MemoryMetadata>): Promise<Memory | Memory[]>;
95
+ remember(content: string, agentId: string, metadata?: Partial<MemoryMetadata>, expiresAt?: string): Promise<Memory | Memory[]>;
95
96
  /**
96
97
  * Delete a specific memory.
97
98
  */
@@ -134,6 +135,8 @@ export declare class MeshOS {
134
135
  adaptiveThreshold?: boolean;
135
136
  useSemanticExpansion?: boolean;
136
137
  filters?: Record<string, unknown>;
138
+ createdAtFilter?: TimestampFilter;
139
+ expiresAtFilter?: TimestampFilter;
137
140
  }): Promise<Memory[]>;
138
141
  /**
139
142
  * Internal method to perform recall with a specific threshold.
@@ -143,4 +146,18 @@ export declare class MeshOS {
143
146
  * Update an agent's status.
144
147
  */
145
148
  updateAgentStatus(agentId: string, status: AgentStatus): Promise<Agent>;
149
+ /**
150
+ * Query memories with flexible filtering, sorting, and pagination.
151
+ */
152
+ getMemories(options: {
153
+ where?: Record<string, unknown>;
154
+ orderBy?: Array<{
155
+ column: string;
156
+ order: 'asc' | 'desc';
157
+ }>;
158
+ limit?: number;
159
+ offset?: number;
160
+ distinct?: boolean;
161
+ distinctOn?: string[];
162
+ }): Promise<Memory[]>;
146
163
  }
@@ -199,7 +199,7 @@ class MeshOS {
199
199
  /**
200
200
  * Store a new memory.
201
201
  */
202
- async remember(content, agentId, metadata) {
202
+ async remember(content, agentId, metadata, expiresAt) {
203
203
  // Create default metadata if none provided
204
204
  const fullMetadata = taxonomy_1.memoryMetadataSchema.parse({
205
205
  type: taxonomy_1.DataType.KNOWLEDGE,
@@ -217,12 +217,13 @@ class MeshOS {
217
217
  const embedding = await this.createEmbedding(content);
218
218
  const embeddingStr = `[${embedding.join(',')}]`;
219
219
  const query = `
220
- mutation Remember($content: String!, $agentId: uuid!, $metadata: jsonb!, $embedding: vector!) {
220
+ mutation Remember($content: String!, $agentId: uuid!, $metadata: jsonb!, $embedding: vector!, $expiresAt: timestamptz) {
221
221
  insert_memories_one(object: {
222
222
  content: $content,
223
223
  agent_id: $agentId,
224
224
  metadata: $metadata,
225
- embedding: $embedding
225
+ embedding: $embedding,
226
+ expires_at: $expiresAt
226
227
  }) {
227
228
  id
228
229
  agent_id
@@ -231,6 +232,7 @@ class MeshOS {
231
232
  embedding
232
233
  created_at
233
234
  updated_at
235
+ expires_at
234
236
  }
235
237
  }
236
238
  `;
@@ -238,15 +240,17 @@ class MeshOS {
238
240
  content,
239
241
  agentId,
240
242
  metadata: fullMetadata,
241
- embedding: embeddingStr
243
+ embedding: embeddingStr,
244
+ expiresAt
242
245
  });
243
246
  // Convert snake_case to camelCase
244
- const { agent_id, created_at, updated_at, ...rest } = result.insert_memories_one;
247
+ const { agent_id, created_at, updated_at, expires_at, ...rest } = result.insert_memories_one;
245
248
  return {
246
249
  ...rest,
247
250
  agentId: agent_id,
248
251
  createdAt: created_at,
249
252
  updatedAt: updated_at,
253
+ expiresAt: expires_at,
250
254
  };
251
255
  }
252
256
  // Split content into chunks
@@ -273,12 +277,13 @@ class MeshOS {
273
277
  const embedding = await this.createEmbedding(chunks[i]);
274
278
  const embeddingStr = `[${embedding.join(',')}]`;
275
279
  const query = `
276
- mutation Remember($content: String!, $agentId: uuid!, $metadata: jsonb!, $embedding: vector!) {
280
+ mutation Remember($content: String!, $agentId: uuid!, $metadata: jsonb!, $embedding: vector!, $expiresAt: timestamptz) {
277
281
  insert_memories_one(object: {
278
282
  content: $content,
279
283
  agent_id: $agentId,
280
284
  metadata: $metadata,
281
- embedding: $embedding
285
+ embedding: $embedding,
286
+ expires_at: $expiresAt
282
287
  }) {
283
288
  id
284
289
  agent_id
@@ -287,6 +292,7 @@ class MeshOS {
287
292
  embedding
288
293
  created_at
289
294
  updated_at
295
+ expires_at
290
296
  }
291
297
  }
292
298
  `;
@@ -294,15 +300,17 @@ class MeshOS {
294
300
  content: chunks[i],
295
301
  agentId,
296
302
  metadata: chunkMetadata,
297
- embedding: embeddingStr
303
+ embedding: embeddingStr,
304
+ expiresAt
298
305
  });
299
306
  // Convert snake_case to camelCase
300
- const { agent_id, created_at, updated_at, ...rest } = result.insert_memories_one;
307
+ const { agent_id, created_at, updated_at, expires_at, ...rest } = result.insert_memories_one;
301
308
  const memory = {
302
309
  ...rest,
303
310
  agentId: agent_id,
304
311
  createdAt: created_at,
305
312
  updatedAt: updated_at,
313
+ expiresAt: expires_at,
306
314
  };
307
315
  memories.push(memory);
308
316
  // Link chunks sequentially
@@ -525,14 +533,16 @@ class MeshOS {
525
533
  * Search memories by semantic similarity.
526
534
  */
527
535
  async recall(options) {
528
- const { query, agentId, limit = 5, threshold = 0.7, minResults = 1, adaptiveThreshold = true, useSemanticExpansion = true, filters } = options;
536
+ const { query, agentId, limit = 5, threshold = 0.7, minResults = 1, adaptiveThreshold = true, useSemanticExpansion = true, filters, createdAtFilter, expiresAtFilter } = options;
529
537
  // First try: Direct search with initial threshold
530
538
  let results = await this.recallWithThreshold({
531
539
  query,
532
540
  threshold,
533
541
  agentId,
534
542
  limit,
535
- filters
543
+ filters,
544
+ createdAtFilter,
545
+ expiresAtFilter
536
546
  });
537
547
  if (results.length >= minResults) {
538
548
  return results.slice(0, limit);
@@ -547,7 +557,9 @@ class MeshOS {
547
557
  threshold: currentThreshold,
548
558
  agentId,
549
559
  limit,
550
- filters
560
+ filters,
561
+ createdAtFilter,
562
+ expiresAtFilter
551
563
  });
552
564
  // Add new results that aren't already in the list
553
565
  for (const result of newResults) {
@@ -573,7 +585,9 @@ class MeshOS {
573
585
  threshold,
574
586
  agentId,
575
587
  limit,
576
- filters
588
+ filters,
589
+ createdAtFilter,
590
+ expiresAtFilter
577
591
  });
578
592
  // Add new results or update if better similarity
579
593
  for (const memory of variationResults) {
@@ -596,7 +610,9 @@ class MeshOS {
596
610
  threshold: currentThreshold,
597
611
  agentId,
598
612
  limit,
599
- filters
613
+ filters,
614
+ createdAtFilter,
615
+ expiresAtFilter
600
616
  });
601
617
  for (const memory of variationResults) {
602
618
  const existingMemory = seenIds.get(memory.id);
@@ -627,7 +643,7 @@ class MeshOS {
627
643
  * Internal method to perform recall with a specific threshold.
628
644
  */
629
645
  async recallWithThreshold(options) {
630
- const { query, threshold, agentId, limit = 10, filters } = options;
646
+ const { query, threshold, agentId, limit = 10, filters, createdAtFilter, expiresAtFilter } = options;
631
647
  // Create embedding for the query
632
648
  const embedding = await this.createEmbedding(query);
633
649
  const embeddingStr = `[${embedding.join(',')}]`;
@@ -638,10 +654,10 @@ class MeshOS {
638
654
  agent_id
639
655
  content
640
656
  metadata
641
- embedding
642
657
  similarity
643
658
  created_at
644
659
  updated_at
660
+ expires_at
645
661
  }
646
662
  }
647
663
  `;
@@ -677,7 +693,9 @@ class MeshOS {
677
693
  match_threshold: threshold,
678
694
  match_count: limit,
679
695
  filter_agent_id: agentId,
680
- metadata_filter: metadataFilter
696
+ metadata_filter: metadataFilter,
697
+ created_at_filter: createdAtFilter,
698
+ expires_at_filter: expiresAtFilter
681
699
  }
682
700
  });
683
701
  return result.search_memories.map(memory => ({
@@ -688,7 +706,8 @@ class MeshOS {
688
706
  embedding: memory.embedding,
689
707
  similarity: memory.similarity,
690
708
  createdAt: memory.created_at,
691
- updatedAt: memory.updated_at
709
+ updatedAt: memory.updated_at,
710
+ expiresAt: memory.expires_at
692
711
  }));
693
712
  }
694
713
  /**
@@ -719,5 +738,56 @@ class MeshOS {
719
738
  }
720
739
  return result.update_agents_by_pk;
721
740
  }
741
+ /**
742
+ * Query memories with flexible filtering, sorting, and pagination.
743
+ */
744
+ async getMemories(options) {
745
+ const { where, orderBy, limit, offset, distinct, distinctOn } = options;
746
+ // Build the GraphQL query dynamically
747
+ const query = `
748
+ query GetMemories(
749
+ $where: memories_bool_exp,
750
+ $orderBy: [memories_order_by!],
751
+ $limit: Int,
752
+ $offset: Int,
753
+ $distinctOn: [memories_select_column!]
754
+ ) {
755
+ memories(
756
+ where: $where,
757
+ order_by: $orderBy,
758
+ limit: $limit,
759
+ offset: $offset,
760
+ distinct: ${distinct ? 'true' : 'false'},
761
+ distinct_on: $distinctOn
762
+ ) {
763
+ id
764
+ agent_id
765
+ content
766
+ metadata
767
+ embedding
768
+ created_at
769
+ updated_at
770
+ expires_at
771
+ }
772
+ }
773
+ `;
774
+ const result = await this.executeQuery(query, {
775
+ where,
776
+ orderBy,
777
+ limit,
778
+ offset,
779
+ distinctOn
780
+ });
781
+ return result.memories.map(memory => ({
782
+ id: memory.id,
783
+ agentId: memory.agent_id,
784
+ content: memory.content,
785
+ metadata: memory.metadata,
786
+ embedding: memory.embedding,
787
+ createdAt: memory.created_at,
788
+ updatedAt: memory.updated_at,
789
+ expiresAt: memory.expires_at
790
+ }));
791
+ }
722
792
  }
723
793
  exports.MeshOS = MeshOS;
@@ -229,3 +229,13 @@ export declare const edgeMetadataSchema: z.ZodObject<{
229
229
  bidirectional?: boolean | undefined;
230
230
  }>;
231
231
  export type EdgeMetadata = z.infer<typeof edgeMetadataSchema>;
232
+ /**
233
+ * Timestamp filter operators
234
+ */
235
+ export interface TimestampFilter {
236
+ _gt?: string;
237
+ _gte?: string;
238
+ _lt?: string;
239
+ _lte?: string;
240
+ _eq?: string;
241
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@props-labs/mesh-os",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "MeshOS - A memory system for AI agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,55 @@
1
+ -- Drop the updated search_memories function
2
+ DROP FUNCTION IF EXISTS public.search_memories(vector(1536), float8, integer, uuid, jsonb, jsonb, jsonb);
3
+
4
+ -- Remove expires_at column
5
+ ALTER TABLE public.memories DROP COLUMN expires_at;
6
+
7
+ -- Drop and recreate the view without expires_at
8
+ DROP VIEW IF EXISTS public.memories_with_similarity;
9
+ CREATE OR REPLACE VIEW public.memories_with_similarity AS
10
+ SELECT
11
+ m.*,
12
+ 0::float8 as similarity
13
+ FROM memories m;
14
+
15
+ -- Restore the previous version of search_memories from 2_metadata_filtering
16
+ CREATE OR REPLACE FUNCTION public.search_memories(
17
+ query_embedding vector(1536),
18
+ match_threshold float8,
19
+ match_count integer,
20
+ filter_agent_id uuid DEFAULT NULL,
21
+ metadata_filter jsonb DEFAULT NULL
22
+ )
23
+ RETURNS SETOF public.memories_with_similarity
24
+ LANGUAGE sql
25
+ STABLE
26
+ AS $$
27
+ WITH normalized_query AS (
28
+ SELECT l2_normalize(query_embedding) AS normalized_vector
29
+ )
30
+ SELECT
31
+ m.id,
32
+ m.agent_id,
33
+ m.content,
34
+ m.metadata,
35
+ m.embedding,
36
+ m.created_at,
37
+ m.updated_at,
38
+ -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) as similarity
39
+ FROM memories m
40
+ WHERE
41
+ CASE
42
+ WHEN filter_agent_id IS NOT NULL THEN m.agent_id = filter_agent_id
43
+ ELSE TRUE
44
+ END
45
+ AND CASE
46
+ WHEN metadata_filter IS NOT NULL THEN m.metadata @> metadata_filter
47
+ ELSE TRUE
48
+ END
49
+ AND -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) >= match_threshold
50
+ ORDER BY -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) DESC
51
+ LIMIT match_count;
52
+ $$;
53
+
54
+ -- Track the function in Hasura
55
+ COMMENT ON FUNCTION public.search_memories IS E'@graphql({"type": "Query"})';
@@ -0,0 +1,108 @@
1
+ -- Add expires_at column to memories table
2
+ ALTER TABLE public.memories ADD COLUMN expires_at TIMESTAMPTZ;
3
+
4
+ -- Create a view for memories with similarity that includes all fields
5
+ DROP VIEW IF EXISTS public.memories_with_similarity;
6
+ CREATE OR REPLACE VIEW public.memories_with_similarity AS
7
+ SELECT
8
+ m.*,
9
+ 0::float8 as similarity -- Default similarity, will be replaced in search
10
+ FROM memories m;
11
+
12
+ -- Drop the existing search_memories function
13
+ DROP FUNCTION IF EXISTS public.search_memories;
14
+
15
+ -- Create the updated search_memories function with standard Hasura filtering
16
+ CREATE OR REPLACE FUNCTION public.search_memories(
17
+ query_embedding vector(1536),
18
+ match_threshold float8,
19
+ match_count integer,
20
+ filter_agent_id uuid DEFAULT NULL,
21
+ metadata_filter jsonb DEFAULT NULL,
22
+ created_at_filter jsonb DEFAULT NULL,
23
+ expires_at_filter jsonb DEFAULT NULL
24
+ )
25
+ RETURNS SETOF public.memories_with_similarity
26
+ LANGUAGE sql
27
+ STABLE
28
+ AS $$
29
+ WITH normalized_query AS (
30
+ SELECT l2_normalize(query_embedding) AS normalized_vector
31
+ )
32
+ SELECT
33
+ m.id,
34
+ m.agent_id,
35
+ m.content,
36
+ m.metadata,
37
+ m.embedding,
38
+ m.created_at,
39
+ m.updated_at,
40
+ m.expires_at,
41
+ -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) as similarity
42
+ FROM memories m
43
+ WHERE
44
+ CASE
45
+ WHEN filter_agent_id IS NOT NULL THEN m.agent_id = filter_agent_id
46
+ ELSE TRUE
47
+ END
48
+ AND CASE
49
+ WHEN metadata_filter IS NOT NULL THEN m.metadata @> metadata_filter
50
+ ELSE TRUE
51
+ END
52
+ AND CASE
53
+ WHEN created_at_filter IS NOT NULL THEN (
54
+ CASE
55
+ WHEN created_at_filter ? '_gt' THEN m.created_at > (created_at_filter->>'_gt')::timestamptz
56
+ ELSE TRUE
57
+ END
58
+ AND CASE
59
+ WHEN created_at_filter ? '_gte' THEN m.created_at >= (created_at_filter->>'_gte')::timestamptz
60
+ ELSE TRUE
61
+ END
62
+ AND CASE
63
+ WHEN created_at_filter ? '_lt' THEN m.created_at < (created_at_filter->>'_lt')::timestamptz
64
+ ELSE TRUE
65
+ END
66
+ AND CASE
67
+ WHEN created_at_filter ? '_lte' THEN m.created_at <= (created_at_filter->>'_lte')::timestamptz
68
+ ELSE TRUE
69
+ END
70
+ AND CASE
71
+ WHEN created_at_filter ? '_eq' THEN m.created_at = (created_at_filter->>'_eq')::timestamptz
72
+ ELSE TRUE
73
+ END
74
+ )
75
+ ELSE TRUE
76
+ END
77
+ AND CASE
78
+ WHEN expires_at_filter IS NOT NULL THEN (
79
+ CASE
80
+ WHEN expires_at_filter ? '_gt' THEN m.expires_at > (expires_at_filter->>'_gt')::timestamptz
81
+ ELSE TRUE
82
+ END
83
+ AND CASE
84
+ WHEN expires_at_filter ? '_gte' THEN m.expires_at >= (expires_at_filter->>'_gte')::timestamptz
85
+ ELSE TRUE
86
+ END
87
+ AND CASE
88
+ WHEN expires_at_filter ? '_lt' THEN m.expires_at < (expires_at_filter->>'_lt')::timestamptz
89
+ ELSE TRUE
90
+ END
91
+ AND CASE
92
+ WHEN expires_at_filter ? '_lte' THEN m.expires_at <= (expires_at_filter->>'_lte')::timestamptz
93
+ ELSE TRUE
94
+ END
95
+ AND CASE
96
+ WHEN expires_at_filter ? '_eq' THEN m.expires_at = (expires_at_filter->>'_eq')::timestamptz
97
+ ELSE TRUE
98
+ END
99
+ )
100
+ ELSE TRUE
101
+ END
102
+ AND -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) >= match_threshold
103
+ ORDER BY -(m.embedding <#> (SELECT normalized_vector FROM normalized_query)) DESC
104
+ LIMIT match_count;
105
+ $$;
106
+
107
+ -- Track the function in Hasura
108
+ COMMENT ON FUNCTION public.search_memories IS E'@graphql({"type": "Query"})';