holosphere 1.1.20 → 2.0.0-alpha0

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 (146) hide show
  1. package/.env.example +36 -0
  2. package/.eslintrc.json +16 -0
  3. package/.prettierrc.json +7 -0
  4. package/README.md +483 -367
  5. package/bin/holosphere-activitypub.js +158 -0
  6. package/cleanup-test-data.js +204 -0
  7. package/examples/demo.html +1333 -0
  8. package/examples/example-bot.js +197 -0
  9. package/package.json +47 -87
  10. package/scripts/check-bundle-size.js +54 -0
  11. package/scripts/check-quest-ids.js +77 -0
  12. package/scripts/import-holons.js +578 -0
  13. package/scripts/publish-to-relay.js +101 -0
  14. package/scripts/read-example.js +186 -0
  15. package/scripts/relay-diagnostic.js +59 -0
  16. package/scripts/relay-example.js +179 -0
  17. package/scripts/resync-to-relay.js +245 -0
  18. package/scripts/revert-import.js +196 -0
  19. package/scripts/test-hybrid-mode.js +108 -0
  20. package/scripts/test-local-storage.js +63 -0
  21. package/scripts/test-nostr-direct.js +55 -0
  22. package/scripts/test-read-data.js +45 -0
  23. package/scripts/test-write-read.js +63 -0
  24. package/scripts/verify-import.js +95 -0
  25. package/scripts/verify-relay-data.js +139 -0
  26. package/src/ai/aggregation.js +319 -0
  27. package/src/ai/breakdown.js +511 -0
  28. package/src/ai/classifier.js +217 -0
  29. package/src/ai/council.js +228 -0
  30. package/src/ai/embeddings.js +279 -0
  31. package/src/ai/federation-ai.js +324 -0
  32. package/src/ai/h3-ai.js +955 -0
  33. package/src/ai/index.js +112 -0
  34. package/src/ai/json-ops.js +225 -0
  35. package/src/ai/llm-service.js +205 -0
  36. package/src/ai/nl-query.js +223 -0
  37. package/src/ai/relationships.js +353 -0
  38. package/src/ai/schema-extractor.js +218 -0
  39. package/src/ai/spatial.js +293 -0
  40. package/src/ai/tts.js +194 -0
  41. package/src/content/social-protocols.js +168 -0
  42. package/src/core/holosphere.js +273 -0
  43. package/src/crypto/secp256k1.js +259 -0
  44. package/src/federation/discovery.js +334 -0
  45. package/src/federation/hologram.js +1042 -0
  46. package/src/federation/registry.js +386 -0
  47. package/src/hierarchical/upcast.js +110 -0
  48. package/src/index.js +2669 -0
  49. package/src/schema/validator.js +91 -0
  50. package/src/spatial/h3-operations.js +110 -0
  51. package/src/storage/backend-factory.js +125 -0
  52. package/src/storage/backend-interface.js +142 -0
  53. package/src/storage/backends/activitypub/server.js +653 -0
  54. package/src/storage/backends/activitypub-backend.js +272 -0
  55. package/src/storage/backends/gundb-backend.js +233 -0
  56. package/src/storage/backends/nostr-backend.js +136 -0
  57. package/src/storage/filesystem-storage-browser.js +41 -0
  58. package/src/storage/filesystem-storage.js +138 -0
  59. package/src/storage/global-tables.js +81 -0
  60. package/src/storage/gun-async.js +281 -0
  61. package/src/storage/gun-wrapper.js +221 -0
  62. package/src/storage/indexeddb-storage.js +122 -0
  63. package/src/storage/key-storage-simple.js +76 -0
  64. package/src/storage/key-storage.js +136 -0
  65. package/src/storage/memory-storage.js +59 -0
  66. package/src/storage/migration.js +338 -0
  67. package/src/storage/nostr-async.js +811 -0
  68. package/src/storage/nostr-client.js +939 -0
  69. package/src/storage/nostr-wrapper.js +211 -0
  70. package/src/storage/outbox-queue.js +208 -0
  71. package/src/storage/persistent-storage.js +109 -0
  72. package/src/storage/sync-service.js +164 -0
  73. package/src/subscriptions/manager.js +142 -0
  74. package/test-ai-real-api.js +202 -0
  75. package/tests/unit/ai/aggregation.test.js +295 -0
  76. package/tests/unit/ai/breakdown.test.js +446 -0
  77. package/tests/unit/ai/classifier.test.js +294 -0
  78. package/tests/unit/ai/council.test.js +262 -0
  79. package/tests/unit/ai/embeddings.test.js +384 -0
  80. package/tests/unit/ai/federation-ai.test.js +344 -0
  81. package/tests/unit/ai/h3-ai.test.js +458 -0
  82. package/tests/unit/ai/index.test.js +304 -0
  83. package/tests/unit/ai/json-ops.test.js +307 -0
  84. package/tests/unit/ai/llm-service.test.js +390 -0
  85. package/tests/unit/ai/nl-query.test.js +383 -0
  86. package/tests/unit/ai/relationships.test.js +311 -0
  87. package/tests/unit/ai/schema-extractor.test.js +384 -0
  88. package/tests/unit/ai/spatial.test.js +279 -0
  89. package/tests/unit/ai/tts.test.js +279 -0
  90. package/tests/unit/content.test.js +332 -0
  91. package/tests/unit/contract/core.test.js +88 -0
  92. package/tests/unit/contract/crypto.test.js +198 -0
  93. package/tests/unit/contract/data.test.js +223 -0
  94. package/tests/unit/contract/federation.test.js +181 -0
  95. package/tests/unit/contract/hierarchical.test.js +113 -0
  96. package/tests/unit/contract/schema.test.js +114 -0
  97. package/tests/unit/contract/social.test.js +217 -0
  98. package/tests/unit/contract/spatial.test.js +110 -0
  99. package/tests/unit/contract/subscriptions.test.js +128 -0
  100. package/tests/unit/contract/utils.test.js +159 -0
  101. package/tests/unit/core.test.js +152 -0
  102. package/tests/unit/crypto.test.js +328 -0
  103. package/tests/unit/federation.test.js +234 -0
  104. package/tests/unit/gun-async.test.js +252 -0
  105. package/tests/unit/hierarchical.test.js +399 -0
  106. package/tests/unit/integration/scenario-01-geographic-storage.test.js +74 -0
  107. package/tests/unit/integration/scenario-02-federation.test.js +76 -0
  108. package/tests/unit/integration/scenario-03-subscriptions.test.js +102 -0
  109. package/tests/unit/integration/scenario-04-validation.test.js +129 -0
  110. package/tests/unit/integration/scenario-05-hierarchy.test.js +125 -0
  111. package/tests/unit/integration/scenario-06-social.test.js +135 -0
  112. package/tests/unit/integration/scenario-07-persistence.test.js +130 -0
  113. package/tests/unit/integration/scenario-08-authorization.test.js +161 -0
  114. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +139 -0
  115. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +357 -0
  116. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +410 -0
  117. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +719 -0
  118. package/tests/unit/performance/benchmark.test.js +85 -0
  119. package/tests/unit/schema.test.js +213 -0
  120. package/tests/unit/spatial.test.js +158 -0
  121. package/tests/unit/storage.test.js +195 -0
  122. package/tests/unit/subscriptions.test.js +328 -0
  123. package/tests/unit/test-data-permanence-debug.js +197 -0
  124. package/tests/unit/test-data-permanence.js +340 -0
  125. package/tests/unit/test-key-persistence-fixed.js +148 -0
  126. package/tests/unit/test-key-persistence.js +172 -0
  127. package/tests/unit/test-relay-permanence.js +376 -0
  128. package/tests/unit/test-second-node.js +95 -0
  129. package/tests/unit/test-simple-write.js +89 -0
  130. package/vite.config.js +49 -0
  131. package/vitest.config.js +20 -0
  132. package/FEDERATION.md +0 -213
  133. package/compute.js +0 -298
  134. package/content.js +0 -980
  135. package/federation.js +0 -1234
  136. package/global.js +0 -736
  137. package/hexlib.js +0 -335
  138. package/hologram.js +0 -183
  139. package/holosphere-bundle.esm.js +0 -33256
  140. package/holosphere-bundle.js +0 -33287
  141. package/holosphere-bundle.min.js +0 -39
  142. package/holosphere.d.ts +0 -601
  143. package/holosphere.js +0 -719
  144. package/node.js +0 -246
  145. package/schema.js +0 -139
  146. package/utils.js +0 -302
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Natural Language Query - Query HoloSphere data using natural language
3
+ */
4
+
5
+ /**
6
+ * NL Query class for natural language to structured query conversion
7
+ */
8
+ export class NLQuery {
9
+ /**
10
+ * @param {LLMService} llmService - LLM service instance
11
+ * @param {Object} holosphere - HoloSphere instance
12
+ */
13
+ constructor(llmService, holosphere = null) {
14
+ this.llm = llmService;
15
+ this.holosphere = holosphere;
16
+ }
17
+
18
+ /**
19
+ * Set HoloSphere instance
20
+ * @param {Object} holosphere - HoloSphere instance
21
+ */
22
+ setHoloSphere(holosphere) {
23
+ this.holosphere = holosphere;
24
+ }
25
+
26
+ /**
27
+ * Parse natural language query into structured format
28
+ * @param {string} query - Natural language query
29
+ * @param {Object} context - Context (available holons, lenses, etc.)
30
+ * @returns {Promise<Object>} Structured query
31
+ */
32
+ async parse(query, context = {}) {
33
+ const systemPrompt = `You are a query parser. Convert natural language queries into structured JSON filters for a geospatial database.
34
+
35
+ Available holons: ${context.holons?.join(', ') || 'any'}
36
+ Available lenses: ${context.lenses?.join(', ') || 'any'}
37
+
38
+ Return a JSON object with:
39
+ {
40
+ "holon": "holon_id or null",
41
+ "lens": "lens_name or null",
42
+ "filters": {
43
+ "field_name": { "op": "eq|ne|gt|gte|lt|lte|contains|in", "value": value }
44
+ },
45
+ "sort": { "field": "field_name", "order": "asc|desc" } or null,
46
+ "limit": number or null,
47
+ "spatial": { "near": "location_name", "radius": "distance" } or null,
48
+ "temporal": { "after": "date", "before": "date" } or null
49
+ }
50
+
51
+ Examples:
52
+ - "show projects near Rome" -> { "lens": "projects", "spatial": { "near": "Rome" } }
53
+ - "find quests with more than 10 participants" -> { "lens": "quests", "filters": { "participants": { "op": "gt", "value": 10 } } }`;
54
+
55
+ const result = await this.llm.getJSON(systemPrompt, query, { temperature: 0.2 });
56
+ return result;
57
+ }
58
+
59
+ /**
60
+ * Execute natural language query
61
+ * @param {string} query - Natural language query
62
+ * @param {Object} options - Query options
63
+ * @returns {Promise<Array>} Query results
64
+ */
65
+ async execute(query, options = {}) {
66
+ if (!this.holosphere) {
67
+ throw new Error('HoloSphere instance required for query execution');
68
+ }
69
+
70
+ // Parse the query
71
+ const parsed = await this.parse(query, options.context);
72
+
73
+ // Get data from HoloSphere
74
+ let results = [];
75
+
76
+ if (parsed.holon && parsed.lens) {
77
+ results = await this.holosphere.getAll(parsed.holon, parsed.lens);
78
+ } else if (parsed.lens) {
79
+ // Search across all holons for this lens (would need holon list)
80
+ if (options.holons) {
81
+ for (const holon of options.holons) {
82
+ const data = await this.holosphere.getAll(holon, parsed.lens);
83
+ results.push(...data.map(item => ({ ...item, _holon: holon })));
84
+ }
85
+ }
86
+ }
87
+
88
+ // Apply filters
89
+ if (parsed.filters) {
90
+ results = this._applyFilters(results, parsed.filters);
91
+ }
92
+
93
+ // Apply sorting
94
+ if (parsed.sort) {
95
+ results = this._applySort(results, parsed.sort);
96
+ }
97
+
98
+ // Apply limit
99
+ if (parsed.limit) {
100
+ results = results.slice(0, parsed.limit);
101
+ }
102
+
103
+ return {
104
+ query,
105
+ parsed,
106
+ results,
107
+ count: results.length,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Apply filters to results
113
+ * @private
114
+ */
115
+ _applyFilters(results, filters) {
116
+ return results.filter(item => {
117
+ for (const [field, condition] of Object.entries(filters)) {
118
+ const value = this._getNestedValue(item, field);
119
+
120
+ if (!this._matchCondition(value, condition)) {
121
+ return false;
122
+ }
123
+ }
124
+ return true;
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Get nested value from object
130
+ * @private
131
+ */
132
+ _getNestedValue(obj, path) {
133
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
134
+ }
135
+
136
+ /**
137
+ * Check if value matches condition
138
+ * @private
139
+ */
140
+ _matchCondition(value, condition) {
141
+ const { op, value: targetValue } = condition;
142
+
143
+ switch (op) {
144
+ case 'eq':
145
+ return value === targetValue;
146
+ case 'ne':
147
+ return value !== targetValue;
148
+ case 'gt':
149
+ return value > targetValue;
150
+ case 'gte':
151
+ return value >= targetValue;
152
+ case 'lt':
153
+ return value < targetValue;
154
+ case 'lte':
155
+ return value <= targetValue;
156
+ case 'contains':
157
+ return String(value).toLowerCase().includes(String(targetValue).toLowerCase());
158
+ case 'in':
159
+ return Array.isArray(targetValue) && targetValue.includes(value);
160
+ default:
161
+ return true;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Apply sorting to results
167
+ * @private
168
+ */
169
+ _applySort(results, sort) {
170
+ const { field, order } = sort;
171
+ const multiplier = order === 'desc' ? -1 : 1;
172
+
173
+ return [...results].sort((a, b) => {
174
+ const aVal = this._getNestedValue(a, field);
175
+ const bVal = this._getNestedValue(b, field);
176
+
177
+ if (aVal < bVal) return -1 * multiplier;
178
+ if (aVal > bVal) return 1 * multiplier;
179
+ return 0;
180
+ });
181
+ }
182
+
183
+ /**
184
+ * Suggest queries based on context
185
+ * @param {Object} context - Current context
186
+ * @returns {Promise<string[]>} Suggested queries
187
+ */
188
+ async suggest(context = {}) {
189
+ const systemPrompt = `Suggest 5 useful natural language queries for exploring geospatial data.
190
+
191
+ Available holons: ${context.holons?.join(', ') || 'geographic areas'}
192
+ Available lenses: ${context.lenses?.join(', ') || 'projects, quests, events, resources'}
193
+
194
+ Return ONLY a JSON array of query strings.`;
195
+
196
+ return this.llm.getJSON(systemPrompt, 'Generate query suggestions', { temperature: 0.7 });
197
+ }
198
+
199
+ /**
200
+ * Explain query results in natural language
201
+ * @param {string} query - Original query
202
+ * @param {Array} results - Query results
203
+ * @returns {Promise<string>} Natural language explanation
204
+ */
205
+ async explain(query, results) {
206
+ const systemPrompt = `You are a helpful data analyst. Explain the results of a query in natural language.
207
+
208
+ Original query: ${query}
209
+ Number of results: ${results.length}
210
+
211
+ Provide a brief, helpful summary of what was found.`;
212
+
213
+ const sampleResults = results.slice(0, 5);
214
+
215
+ return this.llm.sendMessage(
216
+ systemPrompt,
217
+ `Results sample: ${JSON.stringify(sampleResults, null, 2)}`,
218
+ { temperature: 0.5 }
219
+ );
220
+ }
221
+ }
222
+
223
+ export default NLQuery;
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Relationship Discovery - Find hidden connections across data
3
+ */
4
+
5
+ /**
6
+ * Relationship Discovery class
7
+ */
8
+ export class RelationshipDiscovery {
9
+ /**
10
+ * @param {LLMService} llmService - LLM service instance
11
+ * @param {Object} holosphere - HoloSphere instance
12
+ * @param {Object} embeddings - Embeddings instance (optional)
13
+ */
14
+ constructor(llmService, holosphere = null, embeddings = null) {
15
+ this.llm = llmService;
16
+ this.holosphere = holosphere;
17
+ this.embeddings = embeddings;
18
+ }
19
+
20
+ /**
21
+ * Set HoloSphere instance
22
+ * @param {Object} holosphere - HoloSphere instance
23
+ */
24
+ setHoloSphere(holosphere) {
25
+ this.holosphere = holosphere;
26
+ }
27
+
28
+ /**
29
+ * Set Embeddings instance
30
+ * @param {Object} embeddings - Embeddings instance
31
+ */
32
+ setEmbeddings(embeddings) {
33
+ this.embeddings = embeddings;
34
+ }
35
+
36
+ /**
37
+ * Discover relationships in holon data
38
+ * @param {string} holon - Holon identifier
39
+ * @param {string} lens - Lens to analyze (optional)
40
+ * @returns {Promise<Object>} Discovered relationships
41
+ */
42
+ async discoverRelationships(holon, lens = null) {
43
+ if (!this.holosphere) {
44
+ throw new Error('HoloSphere instance required');
45
+ }
46
+
47
+ // Get data from holon
48
+ let data = [];
49
+ const lenses = lens ? [lens] : ['projects', 'quests', 'events', 'resources', 'default'];
50
+
51
+ for (const l of lenses) {
52
+ try {
53
+ const lensData = await this.holosphere.getAll(holon, l);
54
+ data.push(...lensData.map(item => ({ ...item, _lens: l })));
55
+ } catch {
56
+ // Skip unavailable lenses
57
+ }
58
+ }
59
+
60
+ if (data.length < 2) {
61
+ return { holon, relationships: [], message: 'Not enough data for relationship discovery' };
62
+ }
63
+
64
+ const systemPrompt = `You are a relationship discovery expert. Find hidden connections between items in this dataset.
65
+
66
+ Region: ${holon}
67
+ Items: ${data.length}
68
+
69
+ Look for:
70
+ 1. Thematic connections (shared topics, goals)
71
+ 2. Entity connections (shared people, organizations)
72
+ 3. Temporal connections (same timeframes)
73
+ 4. Causal connections (one enables/requires another)
74
+ 5. Geographic connections (same sub-regions)
75
+
76
+ Return JSON:
77
+ {
78
+ "relationships": [
79
+ {
80
+ "item1": {"id": "id1", "title": "title"},
81
+ "item2": {"id": "id2", "title": "title"},
82
+ "type": "thematic|entity|temporal|causal|geographic",
83
+ "strength": 0.0-1.0,
84
+ "description": "relationship description"
85
+ }
86
+ ],
87
+ "clusters": [
88
+ {
89
+ "theme": "cluster theme",
90
+ "items": ["id1", "id2"]
91
+ }
92
+ ],
93
+ "key_entities": ["entity1", "entity2"],
94
+ "summary": "overview of relationship network"
95
+ }`;
96
+
97
+ const relationships = await this.llm.getJSON(
98
+ systemPrompt,
99
+ JSON.stringify(data.slice(0, 40), null, 2),
100
+ { temperature: 0.3 }
101
+ );
102
+
103
+ return {
104
+ holon,
105
+ lens,
106
+ itemCount: data.length,
107
+ relationships,
108
+ timestamp: Date.now(),
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Find items similar to a given item
114
+ * @param {Object} item - Item to find similar items for
115
+ * @param {string} holon - Holon to search in (optional)
116
+ * @param {string} lens - Lens to search in (optional)
117
+ * @param {Object} options - Search options
118
+ * @returns {Promise<Array>} Similar items
119
+ */
120
+ async findSimilar(item, holon = null, lens = null, options = {}) {
121
+ if (!this.holosphere) {
122
+ throw new Error('HoloSphere instance required');
123
+ }
124
+
125
+ const { limit = 10, threshold = 0.5, useEmbeddings = true } = options;
126
+
127
+ // If embeddings available, use semantic search
128
+ if (useEmbeddings && this.embeddings && holon && lens) {
129
+ return this.embeddings.findSimilar(item, holon, lens, { limit, threshold });
130
+ }
131
+
132
+ // Fall back to LLM-based similarity
133
+ if (!holon) {
134
+ throw new Error('Holon required for LLM-based similarity');
135
+ }
136
+
137
+ const searchLenses = lens ? [lens] : ['projects', 'quests', 'events', 'resources', 'default'];
138
+ let candidates = [];
139
+
140
+ for (const l of searchLenses) {
141
+ try {
142
+ const data = await this.holosphere.getAll(holon, l);
143
+ candidates.push(...data.map(d => ({ ...d, _lens: l })));
144
+ } catch {
145
+ // Skip
146
+ }
147
+ }
148
+
149
+ if (candidates.length === 0) {
150
+ return [];
151
+ }
152
+
153
+ const systemPrompt = `Find items most similar to the reference item.
154
+
155
+ Reference item:
156
+ ${JSON.stringify(item, null, 2)}
157
+
158
+ Consider:
159
+ 1. Topic/theme similarity
160
+ 2. Goal alignment
161
+ 3. Participant overlap
162
+ 4. Resource requirements
163
+ 5. Timeline compatibility
164
+
165
+ Return JSON array of similar items with similarity scores:
166
+ [
167
+ {
168
+ "item": {item object},
169
+ "similarity": 0.0-1.0,
170
+ "reasons": ["reason1"]
171
+ }
172
+ ]
173
+
174
+ Order by similarity descending. Max ${limit} items with similarity >= ${threshold}.`;
175
+
176
+ const results = await this.llm.getJSON(
177
+ systemPrompt,
178
+ JSON.stringify(candidates.slice(0, 50), null, 2),
179
+ { temperature: 0.2 }
180
+ );
181
+
182
+ return results.slice(0, limit).filter(r => r.similarity >= threshold);
183
+ }
184
+
185
+ /**
186
+ * Build relationship graph
187
+ * @param {string} holon - Holon
188
+ * @param {string} lens - Lens
189
+ * @returns {Promise<Object>} Graph structure
190
+ */
191
+ async buildGraph(holon, lens) {
192
+ const discovered = await this.discoverRelationships(holon, lens);
193
+
194
+ const nodes = new Map();
195
+ const edges = [];
196
+
197
+ // Build nodes from relationships
198
+ for (const rel of discovered.relationships?.relationships || []) {
199
+ if (!nodes.has(rel.item1.id)) {
200
+ nodes.set(rel.item1.id, { id: rel.item1.id, label: rel.item1.title });
201
+ }
202
+ if (!nodes.has(rel.item2.id)) {
203
+ nodes.set(rel.item2.id, { id: rel.item2.id, label: rel.item2.title });
204
+ }
205
+
206
+ edges.push({
207
+ source: rel.item1.id,
208
+ target: rel.item2.id,
209
+ type: rel.type,
210
+ weight: rel.strength,
211
+ });
212
+ }
213
+
214
+ return {
215
+ nodes: Array.from(nodes.values()),
216
+ edges,
217
+ clusters: discovered.relationships?.clusters || [],
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Find cross-holon relationships
223
+ * @param {string[]} holons - Holons to analyze
224
+ * @param {string} lens - Lens
225
+ * @returns {Promise<Object>} Cross-holon relationships
226
+ */
227
+ async findCrossHolonRelationships(holons, lens) {
228
+ if (!this.holosphere) {
229
+ throw new Error('HoloSphere instance required');
230
+ }
231
+
232
+ const allData = {};
233
+
234
+ for (const holon of holons.slice(0, 5)) {
235
+ try {
236
+ const data = await this.holosphere.getAll(holon, lens);
237
+ if (data.length > 0) {
238
+ allData[holon] = data.slice(0, 15);
239
+ }
240
+ } catch {
241
+ // Skip
242
+ }
243
+ }
244
+
245
+ if (Object.keys(allData).length < 2) {
246
+ return { message: 'Need at least 2 holons with data' };
247
+ }
248
+
249
+ const systemPrompt = `Find relationships between items across different geographic regions.
250
+
251
+ Regions and their data:
252
+ ${JSON.stringify(allData, null, 2)}
253
+
254
+ Identify:
255
+ 1. Cross-region collaborations
256
+ 2. Shared themes across regions
257
+ 3. Potential synergies
258
+ 4. Knowledge transfer opportunities
259
+
260
+ Return JSON:
261
+ {
262
+ "cross_relationships": [
263
+ {
264
+ "holon1": "id",
265
+ "item1": "item_id",
266
+ "holon2": "id",
267
+ "item2": "item_id",
268
+ "type": "type",
269
+ "potential": "collaboration|knowledge_share|synergy"
270
+ }
271
+ ],
272
+ "shared_themes": [{"theme": "theme", "holons": ["id1", "id2"]}],
273
+ "opportunities": ["opp1"]
274
+ }`;
275
+
276
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.4 });
277
+ }
278
+
279
+ /**
280
+ * Suggest connections for an item
281
+ * @param {Object} item - Item to find connections for
282
+ * @param {string} holon - Holon
283
+ * @param {string} lens - Lens
284
+ * @returns {Promise<Object>} Suggested connections
285
+ */
286
+ async suggestConnections(item, holon, lens) {
287
+ const similar = await this.findSimilar(item, holon, lens, { limit: 10 });
288
+
289
+ const systemPrompt = `Based on similar items found, suggest specific actions to create connections.
290
+
291
+ Reference item:
292
+ ${JSON.stringify(item, null, 2)}
293
+
294
+ Similar items found:
295
+ ${JSON.stringify(similar, null, 2)}
296
+
297
+ Suggest:
298
+ 1. Collaboration opportunities
299
+ 2. Resource sharing possibilities
300
+ 3. Joint initiatives
301
+ 4. Knowledge exchange
302
+
303
+ Return JSON:
304
+ {
305
+ "collaborations": [{"with": "item_id", "action": "suggested action"}],
306
+ "resource_sharing": [{"items": ["id1", "id2"], "resource": "what to share"}],
307
+ "initiatives": [{"description": "joint initiative", "participants": ["id1"]}],
308
+ "knowledge_exchange": [{"from": "id", "to": "id", "topic": "topic"}]
309
+ }`;
310
+
311
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.5 });
312
+ }
313
+
314
+ /**
315
+ * Detect relationship patterns
316
+ * @param {string} holon - Holon
317
+ * @param {string} lens - Lens
318
+ * @returns {Promise<Object>} Detected patterns
319
+ */
320
+ async detectPatterns(holon, lens) {
321
+ const relationships = await this.discoverRelationships(holon, lens);
322
+
323
+ const systemPrompt = `Analyze relationships and detect higher-level patterns.
324
+
325
+ Relationships:
326
+ ${JSON.stringify(relationships.relationships, null, 2)}
327
+
328
+ Detect:
329
+ 1. Hub-spoke patterns (central connectors)
330
+ 2. Cluster patterns (tight groups)
331
+ 3. Bridge patterns (connecting different groups)
332
+ 4. Chain patterns (sequential relationships)
333
+ 5. Cyclical patterns (mutual dependencies)
334
+
335
+ Return JSON:
336
+ {
337
+ "patterns": [
338
+ {
339
+ "type": "hub|cluster|bridge|chain|cycle",
340
+ "description": "pattern description",
341
+ "items": ["id1", "id2"],
342
+ "significance": "why this matters"
343
+ }
344
+ ],
345
+ "network_structure": "description of overall structure",
346
+ "recommendations": ["rec1"]
347
+ }`;
348
+
349
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.3 });
350
+ }
351
+ }
352
+
353
+ export default RelationshipDiscovery;