@andespindola/brainlink 0.1.0-beta.50 → 0.1.0-beta.51

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.
@@ -21,6 +21,7 @@ const zoomRecoveryGuardMs = 560
21
21
  const state = {
22
22
  graph: { nodes: [], edges: [] },
23
23
  nodes: [],
24
+ nodeById: new Map(),
24
25
  edges: [],
25
26
  visibleNodes: [],
26
27
  visibleEdges: [],
@@ -555,6 +556,51 @@ const sampleVisibleNodes = (limit = renderNodeBudget, sourceNodes = state.visibl
555
556
  return nodes
556
557
  }
557
558
 
559
+ const enrichSampleWithNeighbors = (nodes) => {
560
+ if (nodes.length === 0) {
561
+ return {
562
+ nodes,
563
+ edges: []
564
+ }
565
+ }
566
+
567
+ const maxNodes = Math.min(renderNodeBudget, nodes.length + 200)
568
+ const expanded = [...nodes]
569
+ const ids = new Set(expanded.map((node) => node.id))
570
+
571
+ for (let index = 0; index < nodes.length && expanded.length < maxNodes; index += 1) {
572
+ const node = nodes[index]
573
+ const candidates = [...(state.visibleEdgeByNode.get(node.id) ?? [])]
574
+ .filter((edge) => edge.target)
575
+ .sort((left, right) => edgeWeight(right) - edgeWeight(left))
576
+ .slice(0, 3)
577
+
578
+ for (let candidateIndex = 0; candidateIndex < candidates.length && expanded.length < maxNodes; candidateIndex += 1) {
579
+ const edge = candidates[candidateIndex]
580
+ const otherId = edge.source === node.id ? edge.target : edge.source
581
+
582
+ if (!otherId || ids.has(otherId)) {
583
+ continue
584
+ }
585
+
586
+ const otherNode = state.nodeById.get(otherId)
587
+ if (!otherNode) {
588
+ continue
589
+ }
590
+
591
+ ids.add(otherId)
592
+ expanded.push(otherNode)
593
+ }
594
+ }
595
+
596
+ const edges = collectVisibleEdgesForNodes(ids)
597
+
598
+ return {
599
+ nodes: expanded,
600
+ edges
601
+ }
602
+ }
603
+
558
604
  const clampScale = value => Math.max(zoomRange.min, Math.min(zoomRange.max, value))
559
605
  const isFiniteNumber = value => Number.isFinite(value)
560
606
  const isReasonableCoordinate = value => isFiniteNumber(value) && Math.abs(value) <= worldCoordinateLimit
@@ -1053,9 +1099,18 @@ const computeRenderVisibility = () => {
1053
1099
  ? sampleVisibleNodes(Math.min(sampleLimit, renderNodeBudget), sourceNodes)
1054
1100
  : sourceNodes.slice(0, Math.min(sourceNodes.length, renderNodeBudget))
1055
1101
  const sampledIds = new Set(sampled.map((node) => node.id))
1102
+ let sampledEdges = state.transform.scale >= 0.035 ? collectVisibleEdgesForNodes(sampledIds) : []
1103
+ let sampledNodes = sampled
1104
+
1105
+ if (state.transform.scale >= 0.035 && sampledEdges.length === 0) {
1106
+ const enriched = enrichSampleWithNeighbors(sampled)
1107
+ sampledNodes = enriched.nodes
1108
+ sampledEdges = enriched.edges
1109
+ }
1110
+
1056
1111
  state.renderClusters = []
1057
- state.renderNodes = sampled
1058
- state.renderEdges = state.transform.scale >= 0.1 ? collectVisibleEdgesForNodes(sampledIds) : []
1112
+ state.renderNodes = sampledNodes
1113
+ state.renderEdges = sampledEdges
1059
1114
  return
1060
1115
  }
1061
1116
 
@@ -1212,11 +1267,13 @@ const render = now => {
1212
1267
  state.offscreenFrameCount = 0
1213
1268
  }
1214
1269
  const minimumEdgeScale =
1215
- state.nodes.length > massiveGraphNodeThreshold
1216
- ? 0.1
1217
- : state.nodes.length > largeGraphNodeThreshold
1218
- ? 0.16
1219
- : 0
1270
+ state.renderNodes.length > 1300
1271
+ ? 0.12
1272
+ : state.renderNodes.length > 900
1273
+ ? 0.085
1274
+ : state.renderNodes.length > 500
1275
+ ? 0.05
1276
+ : 0
1220
1277
  const drawEdges =
1221
1278
  state.renderClusters.length === 0 &&
1222
1279
  state.transform.scale >= minimumEdgeScale
@@ -1627,6 +1684,7 @@ const loadGraph = async (options = { reset: false }) => {
1627
1684
  state.graphSignature = signature
1628
1685
  state.graph = graph
1629
1686
  state.nodes = layout.nodes
1687
+ state.nodeById = new Map(state.nodes.map((node) => [node.id, node]))
1630
1688
  state.edges = layout.edges
1631
1689
  state.nodeDegrees = state.edges.reduce((degrees, edge) => {
1632
1690
  degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + edgeWeight(edge))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/brainlink",
3
- "version": "0.1.0-beta.50",
3
+ "version": "0.1.0-beta.51",
4
4
  "description": "Local-first knowledge memory for agents with Markdown, backlinks, indexing and context retrieval.",
5
5
  "type": "module",
6
6
  "license": "MIT",