@prmichaelsen/remember-mcp 2.2.1 → 2.3.1

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 (69) hide show
  1. package/AGENT.md +98 -5
  2. package/CHANGELOG.md +45 -0
  3. package/README.md +43 -3
  4. package/agent/commands/acp.init.md +376 -0
  5. package/agent/commands/acp.package-install.md +347 -0
  6. package/agent/commands/acp.proceed.md +311 -0
  7. package/agent/commands/acp.report.md +392 -0
  8. package/agent/commands/acp.status.md +280 -0
  9. package/agent/commands/acp.sync.md +323 -0
  10. package/agent/commands/acp.update.md +301 -0
  11. package/agent/commands/acp.validate.md +385 -0
  12. package/agent/commands/acp.version-check-for-updates.md +275 -0
  13. package/agent/commands/acp.version-check.md +190 -0
  14. package/agent/commands/acp.version-update.md +288 -0
  15. package/agent/commands/command.template.md +273 -0
  16. package/agent/design/core-memory-user-profile.md +1253 -0
  17. package/agent/design/ghost-profiles-pseudonymous-identity.md +194 -0
  18. package/agent/design/publish-tools-confirmation-flow.md +922 -0
  19. package/agent/milestones/milestone-10-shared-spaces.md +169 -0
  20. package/agent/progress.yaml +90 -4
  21. package/agent/scripts/install.sh +118 -0
  22. package/agent/scripts/update.sh +22 -10
  23. package/agent/scripts/version.sh +35 -0
  24. package/agent/tasks/task-27-implement-llm-provider-interface.md +51 -0
  25. package/agent/tasks/task-28-implement-llm-provider-factory.md +64 -0
  26. package/agent/tasks/task-29-update-config-for-llm.md +71 -0
  27. package/agent/tasks/task-30-implement-bedrock-provider.md +147 -0
  28. package/agent/tasks/task-31-implement-background-job-service.md +120 -0
  29. package/agent/tasks/task-32-test-llm-provider-integration.md +152 -0
  30. package/agent/tasks/task-34-create-confirmation-token-service.md +191 -0
  31. package/agent/tasks/task-35-create-space-memory-types-schema.md +183 -0
  32. package/agent/tasks/task-36-implement-remember-publish.md +227 -0
  33. package/agent/tasks/task-37-implement-remember-confirm.md +225 -0
  34. package/agent/tasks/task-38-implement-remember-deny.md +161 -0
  35. package/agent/tasks/task-39-implement-remember-search-space.md +188 -0
  36. package/agent/tasks/task-40-implement-remember-query-space.md +193 -0
  37. package/agent/tasks/task-41-configure-firestore-ttl.md +188 -0
  38. package/agent/tasks/task-42-create-tests-shared-spaces.md +216 -0
  39. package/agent/tasks/task-43-update-documentation.md +255 -0
  40. package/agent/tasks/task-44-implement-remember-retract.md +263 -0
  41. package/agent/tasks/task-45-fix-publish-false-success-bug.md +230 -0
  42. package/dist/llm/types.d.ts +1 -0
  43. package/dist/server-factory.js +1000 -1
  44. package/dist/server.js +1002 -3
  45. package/dist/services/confirmation-token.service.d.ts +99 -0
  46. package/dist/services/confirmation-token.service.spec.d.ts +5 -0
  47. package/dist/tools/confirm.d.ts +20 -0
  48. package/dist/tools/deny.d.ts +19 -0
  49. package/dist/tools/publish.d.ts +22 -0
  50. package/dist/tools/query-space.d.ts +28 -0
  51. package/dist/tools/search-space.d.ts +29 -0
  52. package/dist/types/space-memory.d.ts +80 -0
  53. package/dist/weaviate/space-schema.d.ts +59 -0
  54. package/dist/weaviate/space-schema.spec.d.ts +5 -0
  55. package/package.json +1 -1
  56. package/src/llm/types.ts +0 -0
  57. package/src/server-factory.ts +33 -0
  58. package/src/server.ts +33 -0
  59. package/src/services/confirmation-token.service.spec.ts +254 -0
  60. package/src/services/confirmation-token.service.ts +265 -0
  61. package/src/tools/confirm.ts +219 -0
  62. package/src/tools/create-memory.ts +7 -0
  63. package/src/tools/deny.ts +70 -0
  64. package/src/tools/publish.ts +190 -0
  65. package/src/tools/query-space.ts +197 -0
  66. package/src/tools/search-space.ts +189 -0
  67. package/src/types/space-memory.ts +94 -0
  68. package/src/weaviate/space-schema.spec.ts +131 -0
  69. package/src/weaviate/space-schema.ts +275 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * remember_search_space tool
3
+ *
4
+ * Search shared spaces to discover memories from other users.
5
+ * Similar to remember_search_memory but searches space collections.
6
+ */
7
+
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { Filters } from 'weaviate-client';
10
+ import { getWeaviateClient } from '../weaviate/client.js';
11
+ import { ensureSpaceCollection, isValidSpaceId } from '../weaviate/space-schema.js';
12
+ import { SUPPORTED_SPACES } from '../types/space-memory.js';
13
+ import { handleToolError } from '../utils/error-handler.js';
14
+ import type { SearchFilters } from '../types/memory.js';
15
+
16
+ /**
17
+ * Tool definition for remember_search_space
18
+ */
19
+ export const searchSpaceTool: Tool = {
20
+ name: 'remember_search_space',
21
+ description: 'Search shared spaces to discover thoughts, ideas, and memories. Works like remember_search_memory but searches shared spaces instead of personal memories.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: {
25
+ query: {
26
+ type: 'string',
27
+ description: 'Search query (semantic + keyword hybrid)',
28
+ },
29
+ space: {
30
+ type: 'string',
31
+ description: 'Which space to search',
32
+ enum: SUPPORTED_SPACES,
33
+ default: 'the_void',
34
+ },
35
+ content_type: {
36
+ type: 'string',
37
+ description: 'Filter by content type',
38
+ },
39
+ tags: {
40
+ type: 'array',
41
+ items: { type: 'string' },
42
+ description: 'Filter by tags (must have all specified tags)',
43
+ },
44
+ min_weight: {
45
+ type: 'number',
46
+ minimum: 0,
47
+ maximum: 1,
48
+ description: 'Minimum weight/significance (0-1)',
49
+ },
50
+ max_weight: {
51
+ type: 'number',
52
+ minimum: 0,
53
+ maximum: 1,
54
+ description: 'Maximum weight/significance (0-1)',
55
+ },
56
+ date_from: {
57
+ type: 'string',
58
+ description: 'Filter memories created after this date (ISO 8601)',
59
+ },
60
+ date_to: {
61
+ type: 'string',
62
+ description: 'Filter memories created before this date (ISO 8601)',
63
+ },
64
+ limit: {
65
+ type: 'number',
66
+ default: 10,
67
+ description: 'Maximum number of results',
68
+ },
69
+ offset: {
70
+ type: 'number',
71
+ default: 0,
72
+ description: 'Offset for pagination',
73
+ },
74
+ },
75
+ required: ['query', 'space'],
76
+ },
77
+ };
78
+
79
+ interface SearchSpaceArgs {
80
+ query: string;
81
+ space: string;
82
+ content_type?: string;
83
+ tags?: string[];
84
+ min_weight?: number;
85
+ max_weight?: number;
86
+ date_from?: string;
87
+ date_to?: string;
88
+ limit?: number;
89
+ offset?: number;
90
+ }
91
+
92
+ /**
93
+ * Handle remember_search_space tool execution
94
+ */
95
+ export async function handleSearchSpace(
96
+ args: SearchSpaceArgs,
97
+ userId: string // May be used for private spaces in future
98
+ ): Promise<string> {
99
+ try {
100
+ // Validate space ID
101
+ if (!isValidSpaceId(args.space)) {
102
+ return JSON.stringify(
103
+ {
104
+ success: false,
105
+ error: 'Invalid space ID',
106
+ message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`,
107
+ },
108
+ null,
109
+ 2
110
+ );
111
+ }
112
+
113
+ const weaviateClient = getWeaviateClient();
114
+ const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
115
+
116
+ // Build filters for space search
117
+ const filterList: any[] = [];
118
+
119
+ // Filter by space_id
120
+ filterList.push(spaceCollection.filter.byProperty('space_id').equal(args.space));
121
+
122
+ // Filter by doc_type (space_memory)
123
+ filterList.push(spaceCollection.filter.byProperty('doc_type').equal('space_memory'));
124
+
125
+ // Apply content type filter
126
+ if (args.content_type) {
127
+ filterList.push(spaceCollection.filter.byProperty('type').equal(args.content_type));
128
+ }
129
+
130
+ // Apply tags filter
131
+ if (args.tags && args.tags.length > 0) {
132
+ args.tags.forEach(tag => {
133
+ filterList.push(spaceCollection.filter.byProperty('tags').containsAny([tag]));
134
+ });
135
+ }
136
+
137
+ // Apply weight filters
138
+ if (args.min_weight !== undefined) {
139
+ filterList.push(spaceCollection.filter.byProperty('weight').greaterOrEqual(args.min_weight));
140
+ }
141
+
142
+ if (args.max_weight !== undefined) {
143
+ filterList.push(spaceCollection.filter.byProperty('weight').lessOrEqual(args.max_weight));
144
+ }
145
+
146
+ // Apply date filters (convert ISO strings to Date objects)
147
+ if (args.date_from) {
148
+ filterList.push(spaceCollection.filter.byProperty('created_at').greaterOrEqual(new Date(args.date_from)));
149
+ }
150
+
151
+ if (args.date_to) {
152
+ filterList.push(spaceCollection.filter.byProperty('created_at').lessOrEqual(new Date(args.date_to)));
153
+ }
154
+
155
+ const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
156
+
157
+ // Execute hybrid search
158
+ const searchResults = await spaceCollection.query.hybrid(args.query, {
159
+ limit: args.limit || 10,
160
+ offset: args.offset || 0,
161
+ ...(whereFilter && { where: whereFilter }),
162
+ });
163
+
164
+ // Format results
165
+ const memories = searchResults.objects.map((obj) => ({
166
+ id: obj.uuid,
167
+ ...obj.properties,
168
+ _score: obj.metadata?.score,
169
+ }));
170
+
171
+ const result = {
172
+ space: args.space,
173
+ query: args.query,
174
+ memories,
175
+ total: memories.length,
176
+ offset: args.offset || 0,
177
+ limit: args.limit || 10,
178
+ };
179
+
180
+ return JSON.stringify(result, null, 2);
181
+ } catch (error) {
182
+ handleToolError(error, {
183
+ toolName: 'remember_search_space',
184
+ operation: 'search space',
185
+ space: args.space,
186
+ query: args.query,
187
+ });
188
+ }
189
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Space Memory type definitions for remember-mcp
3
+ *
4
+ * Space memories are memories published to shared collections
5
+ * where they can be discovered by other users.
6
+ */
7
+
8
+ import type { Memory, SearchOptions, SearchResult } from './memory.js';
9
+
10
+ /**
11
+ * Space memory - a memory published to a shared space
12
+ *
13
+ * Extends Memory with additional fields for attribution and discovery
14
+ */
15
+ export interface SpaceMemory extends Omit<Memory, 'user_id' | 'doc_type'> {
16
+ /**
17
+ * Space identifier (snake_case)
18
+ * Examples: 'the_void', 'public_space'
19
+ */
20
+ space_id: string;
21
+
22
+ /**
23
+ * Original author's user_id (for permissions)
24
+ * This is private and not shown publicly
25
+ */
26
+ author_id: string;
27
+
28
+ /**
29
+ * Optional ghost profile ID for pseudonymous publishing
30
+ * If present, memory is attributed to ghost instead of user
31
+ */
32
+ ghost_id?: string;
33
+
34
+ /**
35
+ * When the memory was published to the space
36
+ */
37
+ published_at: string;
38
+
39
+ /**
40
+ * How many times this memory has been discovered/viewed
41
+ */
42
+ discovery_count: number;
43
+
44
+ /**
45
+ * Attribution type
46
+ * - 'user': Published as the user (shows author_id)
47
+ * - 'ghost': Published as a ghost (shows ghost_id)
48
+ */
49
+ attribution: 'user' | 'ghost';
50
+
51
+ /**
52
+ * Document type discriminator
53
+ * Always 'space_memory' for space memories
54
+ */
55
+ doc_type: 'space_memory';
56
+ }
57
+
58
+ /**
59
+ * Search options for space memories
60
+ * Same as SearchOptions but for space collections
61
+ */
62
+ export interface SpaceSearchOptions extends Omit<SearchOptions, 'include_relationships'> {
63
+ /**
64
+ * Space to search
65
+ */
66
+ space: string;
67
+ }
68
+
69
+ /**
70
+ * Search result for space memories
71
+ */
72
+ export interface SpaceSearchResult extends Omit<SearchResult, 'memories' | 'relationships'> {
73
+ /**
74
+ * Found space memories
75
+ */
76
+ space_memories: SpaceMemory[];
77
+ }
78
+
79
+ /**
80
+ * Supported space IDs
81
+ */
82
+ export type SpaceId = 'the_void';
83
+
84
+ /**
85
+ * Space display names mapped to IDs
86
+ */
87
+ export const SPACE_DISPLAY_NAMES: Record<SpaceId, string> = {
88
+ the_void: 'The Void',
89
+ };
90
+
91
+ /**
92
+ * Supported spaces constant
93
+ */
94
+ export const SUPPORTED_SPACES: SpaceId[] = ['the_void'];
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Unit tests for Space Schema utilities
3
+ */
4
+
5
+ import {
6
+ getSpaceCollectionName,
7
+ sanitizeSpaceId,
8
+ getSpaceDisplayName,
9
+ isValidSpaceId,
10
+ ensureSpaceCollection,
11
+ } from './space-schema';
12
+ import type { WeaviateClient } from 'weaviate-client';
13
+
14
+ // Mock Weaviate client
15
+ const mockWeaviateClient = {
16
+ collections: {
17
+ exists: jest.fn(),
18
+ create: jest.fn(),
19
+ get: jest.fn(),
20
+ },
21
+ } as unknown as WeaviateClient;
22
+
23
+ describe('Space Schema Utilities', () => {
24
+ beforeEach(() => {
25
+ jest.clearAllMocks();
26
+ });
27
+
28
+ describe('getSpaceCollectionName', () => {
29
+ it('should return collection name with Memory_ prefix', () => {
30
+ expect(getSpaceCollectionName('the_void')).toBe('Memory_the_void');
31
+ expect(getSpaceCollectionName('public_space')).toBe('Memory_public_space');
32
+ });
33
+ });
34
+
35
+ describe('sanitizeSpaceId', () => {
36
+ it('should convert display name to snake_case', () => {
37
+ expect(sanitizeSpaceId('The Void')).toBe('the_void');
38
+ expect(sanitizeSpaceId('Public Space')).toBe('public_space');
39
+ expect(sanitizeSpaceId('MY SPACE')).toBe('my_space');
40
+ });
41
+
42
+ it('should handle multiple spaces', () => {
43
+ expect(sanitizeSpaceId('The Void Space')).toBe('the_void_space');
44
+ });
45
+
46
+ it('should handle already lowercase', () => {
47
+ expect(sanitizeSpaceId('the_void')).toBe('the_void');
48
+ });
49
+ });
50
+
51
+ describe('getSpaceDisplayName', () => {
52
+ it('should return display name for known space IDs', () => {
53
+ expect(getSpaceDisplayName('the_void')).toBe('The Void');
54
+ });
55
+
56
+ it('should return space ID if not found in map', () => {
57
+ expect(getSpaceDisplayName('unknown_space')).toBe('unknown_space');
58
+ });
59
+ });
60
+
61
+ describe('isValidSpaceId', () => {
62
+ it('should return true for supported spaces', () => {
63
+ expect(isValidSpaceId('the_void')).toBe(true);
64
+ });
65
+
66
+ it('should return false for unsupported spaces', () => {
67
+ expect(isValidSpaceId('unknown_space')).toBe(false);
68
+ expect(isValidSpaceId('public_space')).toBe(false); // Not yet supported
69
+ });
70
+ });
71
+
72
+ describe('ensureSpaceCollection', () => {
73
+ it('should return existing collection if it exists', async () => {
74
+ const mockCollection = { name: 'Memory_the_void' };
75
+ (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(true);
76
+ (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue(mockCollection);
77
+
78
+ const result = await ensureSpaceCollection(mockWeaviateClient, 'the_void');
79
+
80
+ expect(result).toBe(mockCollection);
81
+ expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_the_void');
82
+ expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_the_void');
83
+ expect(mockWeaviateClient.collections.create).not.toHaveBeenCalled();
84
+ });
85
+
86
+ it('should create collection if it does not exist', async () => {
87
+ const mockCollection = { name: 'Memory_the_void' };
88
+ (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(false);
89
+ (mockWeaviateClient.collections.create as jest.Mock).mockResolvedValue(undefined);
90
+ (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue(mockCollection);
91
+
92
+ const result = await ensureSpaceCollection(mockWeaviateClient, 'the_void');
93
+
94
+ expect(result).toBe(mockCollection);
95
+ expect(mockWeaviateClient.collections.exists).toHaveBeenCalledWith('Memory_the_void');
96
+ expect(mockWeaviateClient.collections.create).toHaveBeenCalled();
97
+ expect(mockWeaviateClient.collections.get).toHaveBeenCalledWith('Memory_the_void');
98
+ });
99
+
100
+ it('should throw error for invalid space ID', async () => {
101
+ await expect(
102
+ ensureSpaceCollection(mockWeaviateClient, 'invalid_space')
103
+ ).rejects.toThrow('Invalid space ID: invalid_space');
104
+
105
+ expect(mockWeaviateClient.collections.exists).not.toHaveBeenCalled();
106
+ });
107
+
108
+ it('should create collection with correct schema', async () => {
109
+ (mockWeaviateClient.collections.exists as jest.Mock).mockResolvedValue(false);
110
+ (mockWeaviateClient.collections.create as jest.Mock).mockResolvedValue(undefined);
111
+ (mockWeaviateClient.collections.get as jest.Mock).mockReturnValue({});
112
+
113
+ await ensureSpaceCollection(mockWeaviateClient, 'the_void');
114
+
115
+ const createCall = (mockWeaviateClient.collections.create as jest.Mock).mock.calls[0][0];
116
+ expect(createCall.name).toBe('Memory_the_void');
117
+ expect(createCall.vectorizers).toBeDefined();
118
+ expect(createCall.properties).toBeDefined();
119
+ expect(createCall.properties.length).toBeGreaterThan(20); // Should have many properties
120
+
121
+ // Check for space-specific properties
122
+ const propertyNames = createCall.properties.map((p: any) => p.name);
123
+ expect(propertyNames).toContain('space_id');
124
+ expect(propertyNames).toContain('author_id');
125
+ expect(propertyNames).toContain('ghost_id');
126
+ expect(propertyNames).toContain('published_at');
127
+ expect(propertyNames).toContain('discovery_count');
128
+ expect(propertyNames).toContain('attribution');
129
+ });
130
+ });
131
+ });
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Weaviate space collection schema and utilities
3
+ *
4
+ * Manages shared space collections where users can publish memories
5
+ * for discovery by other users.
6
+ */
7
+
8
+ import weaviate, { type WeaviateClient, type Collection } from 'weaviate-client';
9
+ import { config } from '../config.js';
10
+ import { SUPPORTED_SPACES, type SpaceId } from '../types/space-memory.js';
11
+
12
+ /**
13
+ * Get collection name for a space
14
+ *
15
+ * @param spaceId - Space identifier (snake_case)
16
+ * @returns Collection name in format Memory_{space_id}
17
+ *
18
+ * @example
19
+ * getSpaceCollectionName('the_void') // Returns 'Memory_the_void'
20
+ */
21
+ export function getSpaceCollectionName(spaceId: string): string {
22
+ return `Memory_${spaceId}`;
23
+ }
24
+
25
+ /**
26
+ * Sanitize display name to space ID
27
+ *
28
+ * Converts display names like "The Void" to snake_case IDs like "the_void"
29
+ *
30
+ * @param displayName - Display name with spaces and mixed case
31
+ * @returns snake_case space ID
32
+ *
33
+ * @example
34
+ * sanitizeSpaceId('The Void') // Returns 'the_void'
35
+ * sanitizeSpaceId('Public Space') // Returns 'public_space'
36
+ */
37
+ export function sanitizeSpaceId(displayName: string): string {
38
+ return displayName.toLowerCase().replace(/\s+/g, '_');
39
+ }
40
+
41
+ /**
42
+ * Get display name for a space ID
43
+ *
44
+ * @param spaceId - Space identifier
45
+ * @returns Display name or the space ID if not found
46
+ *
47
+ * @example
48
+ * getSpaceDisplayName('the_void') // Returns 'The Void'
49
+ */
50
+ export function getSpaceDisplayName(spaceId: string): string {
51
+ const { SPACE_DISPLAY_NAMES } = require('../types/space-memory.js');
52
+ return SPACE_DISPLAY_NAMES[spaceId as SpaceId] || spaceId;
53
+ }
54
+
55
+ /**
56
+ * Validate space ID
57
+ *
58
+ * @param spaceId - Space identifier to validate
59
+ * @returns True if valid, false otherwise
60
+ */
61
+ export function isValidSpaceId(spaceId: string): boolean {
62
+ return SUPPORTED_SPACES.includes(spaceId as SpaceId);
63
+ }
64
+
65
+ /**
66
+ * Create a space collection with schema
67
+ *
68
+ * @param client - Weaviate client
69
+ * @param spaceId - Space identifier
70
+ */
71
+ async function createSpaceCollection(
72
+ client: WeaviateClient,
73
+ spaceId: string
74
+ ): Promise<void> {
75
+ const collectionName = getSpaceCollectionName(spaceId);
76
+
77
+ console.log(`[Weaviate] Creating space collection ${collectionName}...`);
78
+
79
+ // Create collection with schema (same as Memory schema but for spaces)
80
+ await client.collections.create({
81
+ name: collectionName,
82
+
83
+ // Vectorizer configuration
84
+ vectorizers: weaviate.configure.vectorizer.text2VecOpenAI({
85
+ model: 'text-embedding-3-small',
86
+ // Vectorize content for semantic search
87
+ sourceProperties: ['content', 'observation'],
88
+ }),
89
+
90
+ properties: [
91
+ // Discriminator
92
+ {
93
+ name: 'doc_type',
94
+ dataType: 'text' as any,
95
+ description: 'Document type: "space_memory"',
96
+ },
97
+
98
+ // Space identity
99
+ {
100
+ name: 'space_id',
101
+ dataType: 'text' as any,
102
+ description: 'Space identifier (e.g., "the_void")',
103
+ },
104
+ {
105
+ name: 'author_id',
106
+ dataType: 'text' as any,
107
+ description: 'Original author user_id (for permissions)',
108
+ },
109
+ {
110
+ name: 'ghost_id',
111
+ dataType: 'text' as any,
112
+ description: 'Optional ghost profile ID for pseudonymous publishing',
113
+ },
114
+ {
115
+ name: 'attribution',
116
+ dataType: 'text' as any,
117
+ description: 'Attribution type: "user" or "ghost"',
118
+ },
119
+
120
+ // Discovery metadata
121
+ {
122
+ name: 'published_at',
123
+ dataType: 'text' as any,
124
+ description: 'When published to space (ISO 8601)',
125
+ },
126
+ {
127
+ name: 'discovery_count',
128
+ dataType: 'number' as any,
129
+ description: 'How many times discovered',
130
+ },
131
+
132
+ // Memory fields (same as personal memories)
133
+ {
134
+ name: 'content',
135
+ dataType: 'text' as any,
136
+ description: 'Main memory content (vectorized)',
137
+ },
138
+ {
139
+ name: 'title',
140
+ dataType: 'text' as any,
141
+ description: 'Optional short title',
142
+ },
143
+ {
144
+ name: 'summary',
145
+ dataType: 'text' as any,
146
+ description: 'Optional brief summary',
147
+ },
148
+ {
149
+ name: 'type',
150
+ dataType: 'text' as any,
151
+ description: 'Content type (note, event, person, etc.)',
152
+ },
153
+
154
+ // Scoring fields
155
+ {
156
+ name: 'weight',
157
+ dataType: 'number' as any,
158
+ description: 'Significance/priority (0-1)',
159
+ },
160
+ {
161
+ name: 'trust',
162
+ dataType: 'number' as any,
163
+ description: 'Access control level (0-1)',
164
+ },
165
+ {
166
+ name: 'confidence',
167
+ dataType: 'number' as any,
168
+ description: 'System confidence in accuracy (0-1)',
169
+ },
170
+
171
+ // Location fields (flattened)
172
+ {
173
+ name: 'location_gps_latitude',
174
+ dataType: 'number' as any,
175
+ description: 'GPS latitude',
176
+ },
177
+ {
178
+ name: 'location_gps_longitude',
179
+ dataType: 'number' as any,
180
+ description: 'GPS longitude',
181
+ },
182
+ {
183
+ name: 'location_address_formatted',
184
+ dataType: 'text' as any,
185
+ description: 'Formatted address',
186
+ },
187
+ {
188
+ name: 'location_address_city',
189
+ dataType: 'text' as any,
190
+ description: 'City',
191
+ },
192
+ {
193
+ name: 'location_address_country',
194
+ dataType: 'text' as any,
195
+ description: 'Country',
196
+ },
197
+
198
+ // Context fields (flattened)
199
+ {
200
+ name: 'context_conversation_id',
201
+ dataType: 'text' as any,
202
+ description: 'Conversation ID',
203
+ },
204
+ {
205
+ name: 'context_platform',
206
+ dataType: 'text' as any,
207
+ description: 'Platform where created',
208
+ },
209
+
210
+ // Tags and relationships
211
+ {
212
+ name: 'tags',
213
+ dataType: 'text[]' as any,
214
+ description: 'Tags for categorization',
215
+ },
216
+ {
217
+ name: 'related_memory_ids',
218
+ dataType: 'text[]' as any,
219
+ description: 'IDs of related memories',
220
+ },
221
+
222
+ // Timestamps
223
+ {
224
+ name: 'created_at',
225
+ dataType: 'text' as any,
226
+ description: 'Original creation timestamp (ISO 8601)',
227
+ },
228
+ {
229
+ name: 'updated_at',
230
+ dataType: 'text' as any,
231
+ description: 'Last update timestamp (ISO 8601)',
232
+ },
233
+
234
+ // Versioning
235
+ {
236
+ name: 'version',
237
+ dataType: 'number' as any,
238
+ description: 'Version number (increments on update)',
239
+ },
240
+ ],
241
+ });
242
+
243
+ console.log(`[Weaviate] Space collection ${collectionName} created successfully`);
244
+ }
245
+
246
+ /**
247
+ * Ensure a space collection exists, creating it if needed
248
+ *
249
+ * @param client - Weaviate client
250
+ * @param spaceId - Space identifier
251
+ * @returns Collection reference
252
+ *
253
+ * @example
254
+ * const collection = await ensureSpaceCollection(client, 'the_void');
255
+ */
256
+ export async function ensureSpaceCollection(
257
+ client: WeaviateClient,
258
+ spaceId: string
259
+ ): Promise<Collection<any>> {
260
+ // Validate space ID
261
+ if (!isValidSpaceId(spaceId)) {
262
+ throw new Error(`Invalid space ID: ${spaceId}. Supported spaces: ${SUPPORTED_SPACES.join(', ')}`);
263
+ }
264
+
265
+ const collectionName = getSpaceCollectionName(spaceId);
266
+
267
+ // Check if collection exists
268
+ const exists = await client.collections.exists(collectionName);
269
+
270
+ if (!exists) {
271
+ await createSpaceCollection(client, spaceId);
272
+ }
273
+
274
+ return client.collections.get(collectionName);
275
+ }