holosphere 1.1.19 → 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 +476 -531
  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 -1022
  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 -34549
  140. package/holosphere-bundle.js +0 -34580
  141. package/holosphere-bundle.min.js +0 -49
  142. package/holosphere.d.ts +0 -604
  143. package/holosphere.js +0 -739
  144. package/node.js +0 -246
  145. package/schema.js +0 -139
  146. package/utils.js +0 -302
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Embeddings - Vector embedding generation and semantic search
3
+ */
4
+
5
+ /**
6
+ * Embeddings class for vector operations
7
+ */
8
+ export class Embeddings {
9
+ /**
10
+ * @param {Object} openai - OpenAI client instance
11
+ * @param {Object} holosphere - HoloSphere instance for storage
12
+ */
13
+ constructor(openai, holosphere = null) {
14
+ this.openai = openai;
15
+ this.holosphere = holosphere;
16
+ this.model = 'text-embedding-3-small';
17
+ this.dimensions = 1536;
18
+ }
19
+
20
+ /**
21
+ * Set HoloSphere instance for storage
22
+ * @param {Object} holosphere - HoloSphere instance
23
+ */
24
+ setHoloSphere(holosphere) {
25
+ this.holosphere = holosphere;
26
+ }
27
+
28
+ /**
29
+ * Generate embedding for text
30
+ * @param {string} text - Text to embed
31
+ * @returns {Promise<number[]>} Embedding vector
32
+ */
33
+ async embed(text) {
34
+ try {
35
+ const response = await this.openai.embeddings.create({
36
+ model: this.model,
37
+ input: text,
38
+ });
39
+
40
+ return response.data[0].embedding;
41
+ } catch (error) {
42
+ throw new Error(`Embedding generation failed: ${error.message}`);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Generate embeddings for multiple texts
48
+ * @param {string[]} texts - Array of texts
49
+ * @returns {Promise<number[][]>} Array of embeddings
50
+ */
51
+ async embedBatch(texts) {
52
+ try {
53
+ const response = await this.openai.embeddings.create({
54
+ model: this.model,
55
+ input: texts,
56
+ });
57
+
58
+ return response.data.map(d => d.embedding);
59
+ } catch (error) {
60
+ throw new Error(`Batch embedding failed: ${error.message}`);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Calculate cosine similarity between two vectors
66
+ * @param {number[]} vec1 - First vector
67
+ * @param {number[]} vec2 - Second vector
68
+ * @returns {number} Similarity score (0-1)
69
+ */
70
+ cosineSimilarity(vec1, vec2) {
71
+ if (vec1.length !== vec2.length) {
72
+ throw new Error('Vectors must have same length');
73
+ }
74
+
75
+ let dotProduct = 0;
76
+ let norm1 = 0;
77
+ let norm2 = 0;
78
+
79
+ for (let i = 0; i < vec1.length; i++) {
80
+ dotProduct += vec1[i] * vec2[i];
81
+ norm1 += vec1[i] * vec1[i];
82
+ norm2 += vec2[i] * vec2[i];
83
+ }
84
+
85
+ return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
86
+ }
87
+
88
+ /**
89
+ * Store item with embedding in HoloSphere
90
+ * @param {string} holon - Holon identifier
91
+ * @param {string} lens - Lens name
92
+ * @param {Object} item - Item to store
93
+ * @param {string} textField - Field to embed (default: 'content' or 'text')
94
+ * @returns {Promise<Object>} Stored item with embedding
95
+ */
96
+ async storeWithEmbedding(holon, lens, item, textField = null) {
97
+ if (!this.holosphere) {
98
+ throw new Error('HoloSphere instance required for storage');
99
+ }
100
+
101
+ // Determine text to embed
102
+ const text = textField
103
+ ? item[textField]
104
+ : item.content || item.text || item.description || JSON.stringify(item);
105
+
106
+ if (!text) {
107
+ throw new Error('No text found to embed');
108
+ }
109
+
110
+ // Generate embedding
111
+ const embedding = await this.embed(text);
112
+
113
+ // Store with embedding
114
+ const itemWithEmbedding = {
115
+ ...item,
116
+ _embedding: embedding,
117
+ _embeddedField: textField || 'auto',
118
+ _embeddedAt: Date.now(),
119
+ };
120
+
121
+ await this.holosphere.put(holon, lens, itemWithEmbedding);
122
+
123
+ return itemWithEmbedding;
124
+ }
125
+
126
+ /**
127
+ * Semantic search within a holon/lens
128
+ * @param {string} query - Search query
129
+ * @param {string} holon - Holon identifier
130
+ * @param {string} lens - Lens name
131
+ * @param {Object} options - Search options
132
+ * @returns {Promise<Array<{item: Object, similarity: number}>>} Ranked results
133
+ */
134
+ async semanticSearch(query, holon, lens, options = {}) {
135
+ if (!this.holosphere) {
136
+ throw new Error('HoloSphere instance required for search');
137
+ }
138
+
139
+ const { limit = 10, threshold = 0.5 } = options;
140
+
141
+ // Get query embedding
142
+ const queryEmbedding = await this.embed(query);
143
+
144
+ // Get all items from holon/lens
145
+ const items = await this.holosphere.getAll(holon, lens);
146
+
147
+ // Calculate similarities
148
+ const results = [];
149
+
150
+ for (const item of items) {
151
+ if (item._embedding) {
152
+ const similarity = this.cosineSimilarity(queryEmbedding, item._embedding);
153
+
154
+ if (similarity >= threshold) {
155
+ results.push({
156
+ item: { ...item, _embedding: undefined }, // Don't return embedding
157
+ similarity,
158
+ });
159
+ }
160
+ }
161
+ }
162
+
163
+ // Sort by similarity and limit
164
+ results.sort((a, b) => b.similarity - a.similarity);
165
+
166
+ return results.slice(0, limit);
167
+ }
168
+
169
+ /**
170
+ * Find similar items to a given item
171
+ * @param {Object} item - Item to find similar items for
172
+ * @param {string} holon - Holon identifier
173
+ * @param {string} lens - Lens name
174
+ * @param {Object} options - Search options
175
+ * @returns {Promise<Array>} Similar items
176
+ */
177
+ async findSimilar(item, holon, lens, options = {}) {
178
+ const text = item.content || item.text || item.description || JSON.stringify(item);
179
+ return this.semanticSearch(text, holon, lens, options);
180
+ }
181
+
182
+ /**
183
+ * Cluster items by semantic similarity
184
+ * @param {Object[]} items - Items to cluster
185
+ * @param {number} numClusters - Approximate number of clusters
186
+ * @returns {Promise<Object[][]>} Clustered items
187
+ */
188
+ async cluster(items, numClusters = 5) {
189
+ // Get embeddings for items that don't have them
190
+ const itemsWithEmbeddings = await Promise.all(
191
+ items.map(async (item) => {
192
+ if (item._embedding) {
193
+ return item;
194
+ }
195
+ const text = item.content || item.text || item.description || JSON.stringify(item);
196
+ const embedding = await this.embed(text);
197
+ return { ...item, _embedding: embedding };
198
+ })
199
+ );
200
+
201
+ // Simple k-means clustering
202
+ const clusters = this._kMeans(itemsWithEmbeddings, numClusters);
203
+
204
+ // Return clusters without embeddings
205
+ return clusters.map(cluster =>
206
+ cluster.map(item => ({ ...item, _embedding: undefined }))
207
+ );
208
+ }
209
+
210
+ /**
211
+ * Simple k-means clustering
212
+ * @private
213
+ */
214
+ _kMeans(items, k, maxIterations = 100) {
215
+ if (items.length <= k) {
216
+ return items.map(item => [item]);
217
+ }
218
+
219
+ // Initialize centroids randomly
220
+ const shuffled = [...items].sort(() => Math.random() - 0.5);
221
+ let centroids = shuffled.slice(0, k).map(item => [...item._embedding]);
222
+
223
+ let assignments = new Array(items.length);
224
+
225
+ for (let iter = 0; iter < maxIterations; iter++) {
226
+ // Assign items to nearest centroid
227
+ const newAssignments = items.map((item) => {
228
+ let minDist = Infinity;
229
+ let nearest = 0;
230
+
231
+ for (let c = 0; c < centroids.length; c++) {
232
+ const dist = 1 - this.cosineSimilarity(item._embedding, centroids[c]);
233
+ if (dist < minDist) {
234
+ minDist = dist;
235
+ nearest = c;
236
+ }
237
+ }
238
+
239
+ return nearest;
240
+ });
241
+
242
+ // Check for convergence
243
+ if (JSON.stringify(newAssignments) === JSON.stringify(assignments)) {
244
+ break;
245
+ }
246
+
247
+ assignments = newAssignments;
248
+
249
+ // Update centroids
250
+ for (let c = 0; c < k; c++) {
251
+ const clusterItems = items.filter((_, i) => assignments[i] === c);
252
+
253
+ if (clusterItems.length > 0) {
254
+ centroids[c] = new Array(this.dimensions).fill(0);
255
+
256
+ for (const item of clusterItems) {
257
+ for (let d = 0; d < this.dimensions; d++) {
258
+ centroids[c][d] += item._embedding[d];
259
+ }
260
+ }
261
+
262
+ for (let d = 0; d < this.dimensions; d++) {
263
+ centroids[c][d] /= clusterItems.length;
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ // Group items by cluster
270
+ const clusters = Array.from({ length: k }, () => []);
271
+ items.forEach((item, i) => {
272
+ clusters[assignments[i]].push(item);
273
+ });
274
+
275
+ return clusters.filter(c => c.length > 0);
276
+ }
277
+ }
278
+
279
+ export default Embeddings;
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Federation Advisor - AI-powered federation suggestions and analysis
3
+ */
4
+
5
+ /**
6
+ * Federation Advisor class
7
+ */
8
+ export class FederationAdvisor {
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
+ * Suggest federations based on content similarity
38
+ * @param {string} holon - Holon to find federation partners for
39
+ * @param {Object} options - Options
40
+ * @returns {Promise<Array>} Suggested federations
41
+ */
42
+ async suggestFederations(holon, options = {}) {
43
+ if (!this.holosphere) {
44
+ throw new Error('HoloSphere instance required');
45
+ }
46
+
47
+ const { candidateHolons = [], lens = 'default', maxSuggestions = 5 } = options;
48
+
49
+ // Get data from source holon
50
+ const sourceData = await this.holosphere.getAll(holon, lens);
51
+
52
+ if (sourceData.length === 0) {
53
+ return { holon, suggestions: [], message: 'No data in source holon' };
54
+ }
55
+
56
+ // If we have candidate holons, compare with each
57
+ const comparisons = [];
58
+
59
+ for (const candidate of candidateHolons.slice(0, 10)) {
60
+ if (candidate === holon) continue;
61
+
62
+ try {
63
+ const candidateData = await this.holosphere.getAll(candidate, lens);
64
+ if (candidateData.length > 0) {
65
+ comparisons.push({
66
+ holon: candidate,
67
+ dataCount: candidateData.length,
68
+ dataSample: candidateData.slice(0, 10),
69
+ });
70
+ }
71
+ } catch {
72
+ // Skip unavailable holons
73
+ }
74
+ }
75
+
76
+ if (comparisons.length === 0) {
77
+ return { holon, suggestions: [], message: 'No candidate holons with data' };
78
+ }
79
+
80
+ const systemPrompt = `You are a federation advisor. Analyze which regions would benefit from federating (sharing data) with the source region.
81
+
82
+ Source region: ${holon}
83
+ Source data count: ${sourceData.length}
84
+
85
+ Consider:
86
+ 1. Content similarity - similar topics benefit from shared visibility
87
+ 2. Complementary content - different but related content enables collaboration
88
+ 3. Geographic proximity relevance
89
+ 4. Potential for knowledge sharing
90
+
91
+ Return JSON array:
92
+ [
93
+ {
94
+ "holon": "id",
95
+ "score": 0.0-1.0,
96
+ "reasoning": "why federate",
97
+ "benefits": ["benefit1"],
98
+ "type": "similarity|complementary|geographic"
99
+ }
100
+ ]
101
+
102
+ Order by score descending, max ${maxSuggestions} suggestions.`;
103
+
104
+ const userMessage = `Source data sample:
105
+ ${JSON.stringify(sourceData.slice(0, 15), null, 2)}
106
+
107
+ Candidate regions:
108
+ ${JSON.stringify(comparisons, null, 2)}`;
109
+
110
+ const suggestions = await this.llm.getJSON(systemPrompt, userMessage, { temperature: 0.3 });
111
+
112
+ return {
113
+ holon,
114
+ lens,
115
+ suggestions: suggestions.slice(0, maxSuggestions),
116
+ timestamp: Date.now(),
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Analyze federation health
122
+ * @param {string} holon - Holon to analyze
123
+ * @returns {Promise<Object>} Federation health analysis
124
+ */
125
+ async analyzeFederationHealth(holon) {
126
+ if (!this.holosphere) {
127
+ throw new Error('HoloSphere instance required');
128
+ }
129
+
130
+ // Get federation info
131
+ const federation = await this.holosphere.getFederation(holon);
132
+
133
+ if (!federation || !federation.federation || federation.federation.length === 0) {
134
+ return {
135
+ holon,
136
+ health: 'none',
137
+ message: 'No federations configured',
138
+ score: 0,
139
+ };
140
+ }
141
+
142
+ // Analyze each federation
143
+ const federationAnalysis = [];
144
+
145
+ for (const fedHolon of federation.federation.slice(0, 5)) {
146
+ try {
147
+ const fedData = await this.holosphere.getAll(fedHolon, 'default');
148
+ federationAnalysis.push({
149
+ holon: fedHolon,
150
+ active: fedData.length > 0,
151
+ dataCount: fedData.length,
152
+ });
153
+ } catch {
154
+ federationAnalysis.push({
155
+ holon: fedHolon,
156
+ active: false,
157
+ error: true,
158
+ });
159
+ }
160
+ }
161
+
162
+ const systemPrompt = `You are a federation health analyst. Assess the health of this holon's federation relationships.
163
+
164
+ Source holon: ${holon}
165
+ Federation partners: ${federation.federation.length}
166
+ Active federations: ${federationAnalysis.filter(f => f.active).length}
167
+
168
+ Federation details:
169
+ ${JSON.stringify(federationAnalysis, null, 2)}
170
+
171
+ Analyze:
172
+ 1. Overall federation health
173
+ 2. Active vs inactive relationships
174
+ 3. Balance of the federation network
175
+ 4. Recommendations
176
+
177
+ Return JSON:
178
+ {
179
+ "health_score": 0.0-1.0,
180
+ "status": "healthy|degraded|unhealthy",
181
+ "active_count": n,
182
+ "inactive_count": n,
183
+ "issues": ["issue1"],
184
+ "recommendations": ["rec1"],
185
+ "summary": "text"
186
+ }`;
187
+
188
+ const analysis = await this.llm.getJSON(systemPrompt, '', { temperature: 0.3 });
189
+
190
+ return {
191
+ holon,
192
+ federation: federation.federation,
193
+ analysis,
194
+ timestamp: Date.now(),
195
+ };
196
+ }
197
+
198
+ /**
199
+ * Suggest federation optimizations
200
+ * @param {string} holon - Holon to optimize
201
+ * @returns {Promise<Object>} Optimization suggestions
202
+ */
203
+ async optimizeFederation(holon) {
204
+ const health = await this.analyzeFederationHealth(holon);
205
+
206
+ if (health.health === 'none') {
207
+ return { holon, suggestions: ['Consider establishing initial federations'] };
208
+ }
209
+
210
+ const systemPrompt = `Based on federation health analysis, suggest optimizations.
211
+
212
+ Health analysis:
213
+ ${JSON.stringify(health.analysis, null, 2)}
214
+
215
+ Suggest:
216
+ 1. Federations to strengthen
217
+ 2. Federations to reconsider
218
+ 3. New potential federations
219
+ 4. Data flow improvements
220
+
221
+ Return JSON:
222
+ {
223
+ "strengthen": ["holon_id"],
224
+ "reconsider": ["holon_id"],
225
+ "new_potential": ["description"],
226
+ "improvements": ["improvement1"],
227
+ "priority": "high|medium|low"
228
+ }`;
229
+
230
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.4 });
231
+ }
232
+
233
+ /**
234
+ * Analyze data flow in federation network
235
+ * @param {string} holon - Starting holon
236
+ * @returns {Promise<Object>} Data flow analysis
237
+ */
238
+ async analyzeDataFlow(holon) {
239
+ if (!this.holosphere) {
240
+ throw new Error('HoloSphere instance required');
241
+ }
242
+
243
+ const federation = await this.holosphere.getFederation(holon);
244
+
245
+ if (!federation) {
246
+ return { holon, message: 'No federation configured' };
247
+ }
248
+
249
+ const systemPrompt = `Analyze the data flow patterns in a federation network.
250
+
251
+ Source holon: ${holon}
252
+ Federated with: ${federation.federation?.join(', ') || 'none'}
253
+ Notifies: ${federation.notify?.join(', ') || 'none'}
254
+
255
+ Consider:
256
+ 1. Bidirectional vs unidirectional relationships
257
+ 2. Hub patterns (many connections)
258
+ 3. Data propagation paths
259
+ 4. Potential bottlenecks
260
+
261
+ Return JSON:
262
+ {
263
+ "flow_type": "bidirectional|unidirectional|mixed",
264
+ "topology": "hub|mesh|chain|star",
265
+ "propagation_depth": n,
266
+ "bottlenecks": ["desc"],
267
+ "recommendations": ["rec1"]
268
+ }`;
269
+
270
+ return this.llm.getJSON(systemPrompt, JSON.stringify(federation, null, 2), { temperature: 0.3 });
271
+ }
272
+
273
+ /**
274
+ * Find federation bridges - holons that connect disparate networks
275
+ * @param {string[]} holons - List of holons to analyze
276
+ * @returns {Promise<Object>} Bridge analysis
277
+ */
278
+ async findBridges(holons) {
279
+ if (!this.holosphere) {
280
+ throw new Error('HoloSphere instance required');
281
+ }
282
+
283
+ const network = [];
284
+
285
+ for (const holon of holons.slice(0, 20)) {
286
+ try {
287
+ const fed = await this.holosphere.getFederation(holon);
288
+ if (fed) {
289
+ network.push({
290
+ holon,
291
+ federations: fed.federation || [],
292
+ notifies: fed.notify || [],
293
+ });
294
+ }
295
+ } catch {
296
+ // Skip
297
+ }
298
+ }
299
+
300
+ const systemPrompt = `Analyze a federation network to identify bridge holons (connectors between clusters).
301
+
302
+ Network:
303
+ ${JSON.stringify(network, null, 2)}
304
+
305
+ Identify:
306
+ 1. Bridge holons that connect clusters
307
+ 2. Isolated holons
308
+ 3. Central hubs
309
+ 4. Network clusters
310
+
311
+ Return JSON:
312
+ {
313
+ "bridges": [{"holon": "id", "connects": ["cluster1", "cluster2"]}],
314
+ "isolated": ["holon_id"],
315
+ "hubs": [{"holon": "id", "connections": n}],
316
+ "clusters": [["holon1", "holon2"]],
317
+ "network_health": 0.0-1.0
318
+ }`;
319
+
320
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.3 });
321
+ }
322
+ }
323
+
324
+ export default FederationAdvisor;