network-ai 5.10.1 → 5.11.0
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.
- package/INTEGRATION_GUIDE.md +2 -2
- package/README.md +5 -3
- package/SKILL.md +3 -3
- package/dist/esm/adapters/a2a-adapter.js +235 -0
- package/dist/esm/adapters/a2a-adapter.js.map +1 -0
- package/dist/esm/adapters/adapter-registry.js +613 -0
- package/dist/esm/adapters/adapter-registry.js.map +1 -0
- package/dist/esm/adapters/agno-adapter.js +140 -0
- package/dist/esm/adapters/agno-adapter.js.map +1 -0
- package/dist/esm/adapters/anthropic-computer-use-adapter.js +180 -0
- package/dist/esm/adapters/anthropic-computer-use-adapter.js.map +1 -0
- package/dist/esm/adapters/aps-adapter.js +289 -0
- package/dist/esm/adapters/aps-adapter.js.map +1 -0
- package/dist/esm/adapters/autogen-adapter.js +141 -0
- package/dist/esm/adapters/autogen-adapter.js.map +1 -0
- package/dist/esm/adapters/base-adapter.js +104 -0
- package/dist/esm/adapters/base-adapter.js.map +1 -0
- package/dist/esm/adapters/browser-agent-adapter.js +219 -0
- package/dist/esm/adapters/browser-agent-adapter.js.map +1 -0
- package/dist/esm/adapters/codex-adapter.js +318 -0
- package/dist/esm/adapters/codex-adapter.js.map +1 -0
- package/dist/esm/adapters/copilot-adapter.js +132 -0
- package/dist/esm/adapters/copilot-adapter.js.map +1 -0
- package/dist/esm/adapters/crewai-adapter.js +148 -0
- package/dist/esm/adapters/crewai-adapter.js.map +1 -0
- package/dist/esm/adapters/custom-adapter.js +142 -0
- package/dist/esm/adapters/custom-adapter.js.map +1 -0
- package/dist/esm/adapters/custom-streaming-adapter.js +181 -0
- package/dist/esm/adapters/custom-streaming-adapter.js.map +1 -0
- package/dist/esm/adapters/dspy-adapter.js +127 -0
- package/dist/esm/adapters/dspy-adapter.js.map +1 -0
- package/dist/esm/adapters/haystack-adapter.js +149 -0
- package/dist/esm/adapters/haystack-adapter.js.map +1 -0
- package/dist/esm/adapters/hermes-adapter.js +217 -0
- package/dist/esm/adapters/hermes-adapter.js.map +1 -0
- package/dist/esm/adapters/index.js +109 -0
- package/dist/esm/adapters/index.js.map +1 -0
- package/dist/esm/adapters/langchain-adapter.js +134 -0
- package/dist/esm/adapters/langchain-adapter.js.map +1 -0
- package/dist/esm/adapters/langchain-streaming-adapter.js +161 -0
- package/dist/esm/adapters/langchain-streaming-adapter.js.map +1 -0
- package/dist/esm/adapters/langgraph-adapter.js +119 -0
- package/dist/esm/adapters/langgraph-adapter.js.map +1 -0
- package/dist/esm/adapters/llamaindex-adapter.js +135 -0
- package/dist/esm/adapters/llamaindex-adapter.js.map +1 -0
- package/dist/esm/adapters/mcp-adapter.js +200 -0
- package/dist/esm/adapters/mcp-adapter.js.map +1 -0
- package/dist/esm/adapters/minimax-adapter.js +233 -0
- package/dist/esm/adapters/minimax-adapter.js.map +1 -0
- package/dist/esm/adapters/nemoclaw-adapter.js +465 -0
- package/dist/esm/adapters/nemoclaw-adapter.js.map +1 -0
- package/dist/esm/adapters/openai-agents-adapter.js +118 -0
- package/dist/esm/adapters/openai-agents-adapter.js.map +1 -0
- package/dist/esm/adapters/openai-assistants-adapter.js +130 -0
- package/dist/esm/adapters/openai-assistants-adapter.js.map +1 -0
- package/dist/esm/adapters/openclaw-adapter.js +107 -0
- package/dist/esm/adapters/openclaw-adapter.js.map +1 -0
- package/dist/esm/adapters/orchestrator-adapter.js +218 -0
- package/dist/esm/adapters/orchestrator-adapter.js.map +1 -0
- package/dist/esm/adapters/pydantic-ai-adapter.js +163 -0
- package/dist/esm/adapters/pydantic-ai-adapter.js.map +1 -0
- package/dist/esm/adapters/rlm-adapter.js +167 -0
- package/dist/esm/adapters/rlm-adapter.js.map +1 -0
- package/dist/esm/adapters/semantic-kernel-adapter.js +123 -0
- package/dist/esm/adapters/semantic-kernel-adapter.js.map +1 -0
- package/dist/esm/adapters/streaming-base-adapter.js +74 -0
- package/dist/esm/adapters/streaming-base-adapter.js.map +1 -0
- package/dist/esm/adapters/vertex-ai-adapter.js +166 -0
- package/dist/esm/adapters/vertex-ai-adapter.js.map +1 -0
- package/dist/esm/demo-control-plane.js +147 -0
- package/dist/esm/demo-control-plane.js.map +1 -0
- package/dist/esm/demo-worktree-dashboard.js +131 -0
- package/dist/esm/demo-worktree-dashboard.js.map +1 -0
- package/dist/esm/examples/01-hello-swarm.js +165 -0
- package/dist/esm/examples/01-hello-swarm.js.map +1 -0
- package/dist/esm/examples/02-fsm-pipeline.js +189 -0
- package/dist/esm/examples/02-fsm-pipeline.js.map +1 -0
- package/dist/esm/examples/03-parallel-agents.js +192 -0
- package/dist/esm/examples/03-parallel-agents.js.map +1 -0
- package/dist/esm/examples/05-code-review-swarm.js +1177 -0
- package/dist/esm/examples/05-code-review-swarm.js.map +1 -0
- package/dist/esm/examples/06-ai-pipeline-demo.js +263 -0
- package/dist/esm/examples/06-ai-pipeline-demo.js.map +1 -0
- package/dist/esm/examples/07-full-showcase.js +946 -0
- package/dist/esm/examples/07-full-showcase.js.map +1 -0
- package/dist/esm/examples/08-control-plane-stress-demo.js +186 -0
- package/dist/esm/examples/08-control-plane-stress-demo.js.map +1 -0
- package/dist/esm/examples/09-real-langchain.js +231 -0
- package/dist/esm/examples/09-real-langchain.js.map +1 -0
- package/dist/esm/examples/10-nemoclaw-sandbox-swarm.js +270 -0
- package/dist/esm/examples/10-nemoclaw-sandbox-swarm.js.map +1 -0
- package/dist/esm/examples/demo-runner.js +119 -0
- package/dist/esm/examples/demo-runner.js.map +1 -0
- package/dist/esm/index.js +1352 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/adapter-hooks.js +216 -0
- package/dist/esm/lib/adapter-hooks.js.map +1 -0
- package/dist/esm/lib/adapter-test-harness.js +118 -0
- package/dist/esm/lib/adapter-test-harness.js.map +1 -0
- package/dist/esm/lib/agent-conversation.js +155 -0
- package/dist/esm/lib/agent-conversation.js.map +1 -0
- package/dist/esm/lib/agent-debate.js +146 -0
- package/dist/esm/lib/agent-debate.js.map +1 -0
- package/dist/esm/lib/agent-memory.js +336 -0
- package/dist/esm/lib/agent-memory.js.map +1 -0
- package/dist/esm/lib/agent-runtime.js +818 -0
- package/dist/esm/lib/agent-runtime.js.map +1 -0
- package/dist/esm/lib/agent-vcr.js +218 -0
- package/dist/esm/lib/agent-vcr.js.map +1 -0
- package/dist/esm/lib/anomaly-detector.js +178 -0
- package/dist/esm/lib/anomaly-detector.js.map +1 -0
- package/dist/esm/lib/approval-inbox.js +385 -0
- package/dist/esm/lib/approval-inbox.js.map +1 -0
- package/dist/esm/lib/auth-guardian.js +692 -0
- package/dist/esm/lib/auth-guardian.js.map +1 -0
- package/dist/esm/lib/auth-validator.js +32 -0
- package/dist/esm/lib/auth-validator.js.map +1 -0
- package/dist/esm/lib/blackboard-backend-crdt.js +251 -0
- package/dist/esm/lib/blackboard-backend-crdt.js.map +1 -0
- package/dist/esm/lib/blackboard-backend-redis.js +244 -0
- package/dist/esm/lib/blackboard-backend-redis.js.map +1 -0
- package/dist/esm/lib/blackboard-backend.js +141 -0
- package/dist/esm/lib/blackboard-backend.js.map +1 -0
- package/dist/esm/lib/blackboard-validator.js +985 -0
- package/dist/esm/lib/blackboard-validator.js.map +1 -0
- package/dist/esm/lib/circuit-breaker.js +164 -0
- package/dist/esm/lib/circuit-breaker.js.map +1 -0
- package/dist/esm/lib/claim-verifier.js +173 -0
- package/dist/esm/lib/claim-verifier.js.map +1 -0
- package/dist/esm/lib/comparison-runner.js +138 -0
- package/dist/esm/lib/comparison-runner.js.map +1 -0
- package/dist/esm/lib/compliance-monitor.js +261 -0
- package/dist/esm/lib/compliance-monitor.js.map +1 -0
- package/dist/esm/lib/confidence-filter.js +210 -0
- package/dist/esm/lib/confidence-filter.js.map +1 -0
- package/dist/esm/lib/config-watcher.js +215 -0
- package/dist/esm/lib/config-watcher.js.map +1 -0
- package/dist/esm/lib/consistency.js +274 -0
- package/dist/esm/lib/consistency.js.map +1 -0
- package/dist/esm/lib/console-ui.js +276 -0
- package/dist/esm/lib/console-ui.js.map +1 -0
- package/dist/esm/lib/context-throttler.js +171 -0
- package/dist/esm/lib/context-throttler.js.map +1 -0
- package/dist/esm/lib/control-plane.js +527 -0
- package/dist/esm/lib/control-plane.js.map +1 -0
- package/dist/esm/lib/cost-governor.js +128 -0
- package/dist/esm/lib/cost-governor.js.map +1 -0
- package/dist/esm/lib/cost-heatmap.js +161 -0
- package/dist/esm/lib/cost-heatmap.js.map +1 -0
- package/dist/esm/lib/coverage-gate.js +213 -0
- package/dist/esm/lib/coverage-gate.js.map +1 -0
- package/dist/esm/lib/coverage-reporter.js +177 -0
- package/dist/esm/lib/coverage-reporter.js.map +1 -0
- package/dist/esm/lib/crdt.js +141 -0
- package/dist/esm/lib/crdt.js.map +1 -0
- package/dist/esm/lib/dashboard-server.js +403 -0
- package/dist/esm/lib/dashboard-server.js.map +1 -0
- package/dist/esm/lib/dry-run.js +130 -0
- package/dist/esm/lib/dry-run.js.map +1 -0
- package/dist/esm/lib/env-manager.js +518 -0
- package/dist/esm/lib/env-manager.js.map +1 -0
- package/dist/esm/lib/errors.js +201 -0
- package/dist/esm/lib/errors.js.map +1 -0
- package/dist/esm/lib/event-bus.js +229 -0
- package/dist/esm/lib/event-bus.js.map +1 -0
- package/dist/esm/lib/explainability.js +102 -0
- package/dist/esm/lib/explainability.js.map +1 -0
- package/dist/esm/lib/fan-out.js +237 -0
- package/dist/esm/lib/fan-out.js.map +1 -0
- package/dist/esm/lib/federated-budget.js +322 -0
- package/dist/esm/lib/federated-budget.js.map +1 -0
- package/dist/esm/lib/fsm-journey.js +478 -0
- package/dist/esm/lib/fsm-journey.js.map +1 -0
- package/dist/esm/lib/goal-decomposer.js +698 -0
- package/dist/esm/lib/goal-decomposer.js.map +1 -0
- package/dist/esm/lib/goal-dsl.js +391 -0
- package/dist/esm/lib/goal-dsl.js.map +1 -0
- package/dist/esm/lib/job-queue.js +310 -0
- package/dist/esm/lib/job-queue.js.map +1 -0
- package/dist/esm/lib/landscape-agent.js +134 -0
- package/dist/esm/lib/landscape-agent.js.map +1 -0
- package/dist/esm/lib/learning-loop.js +181 -0
- package/dist/esm/lib/learning-loop.js.map +1 -0
- package/dist/esm/lib/lifecycle-hooks.js +148 -0
- package/dist/esm/lib/lifecycle-hooks.js.map +1 -0
- package/dist/esm/lib/locked-blackboard.js +1295 -0
- package/dist/esm/lib/locked-blackboard.js.map +1 -0
- package/dist/esm/lib/logger.js +150 -0
- package/dist/esm/lib/logger.js.map +1 -0
- package/dist/esm/lib/mcp-blackboard-tools.js +298 -0
- package/dist/esm/lib/mcp-blackboard-tools.js.map +1 -0
- package/dist/esm/lib/mcp-bridge.js +357 -0
- package/dist/esm/lib/mcp-bridge.js.map +1 -0
- package/dist/esm/lib/mcp-tool-consumer.js +287 -0
- package/dist/esm/lib/mcp-tool-consumer.js.map +1 -0
- package/dist/esm/lib/mcp-tools-control.js +392 -0
- package/dist/esm/lib/mcp-tools-control.js.map +1 -0
- package/dist/esm/lib/mcp-tools-extended.js +371 -0
- package/dist/esm/lib/mcp-tools-extended.js.map +1 -0
- package/dist/esm/lib/mcp-transport-http.js +528 -0
- package/dist/esm/lib/mcp-transport-http.js.map +1 -0
- package/dist/esm/lib/mcp-transport-sse.js +503 -0
- package/dist/esm/lib/mcp-transport-sse.js.map +1 -0
- package/dist/esm/lib/metrics.js +284 -0
- package/dist/esm/lib/metrics.js.map +1 -0
- package/dist/esm/lib/orchestrator-types.js +66 -0
- package/dist/esm/lib/orchestrator-types.js.map +1 -0
- package/dist/esm/lib/otel-bridge.js +167 -0
- package/dist/esm/lib/otel-bridge.js.map +1 -0
- package/dist/esm/lib/partition-planner.js +246 -0
- package/dist/esm/lib/partition-planner.js.map +1 -0
- package/dist/esm/lib/phase-pipeline.js +367 -0
- package/dist/esm/lib/phase-pipeline.js.map +1 -0
- package/dist/esm/lib/playground.js +224 -0
- package/dist/esm/lib/playground.js.map +1 -0
- package/dist/esm/lib/qa-orchestrator.js +296 -0
- package/dist/esm/lib/qa-orchestrator.js.map +1 -0
- package/dist/esm/lib/quadtree.js +259 -0
- package/dist/esm/lib/quadtree.js.map +1 -0
- package/dist/esm/lib/route-classifier.js +217 -0
- package/dist/esm/lib/route-classifier.js.map +1 -0
- package/dist/esm/lib/semantic-search.js +235 -0
- package/dist/esm/lib/semantic-search.js.map +1 -0
- package/dist/esm/lib/shared-blackboard.js +249 -0
- package/dist/esm/lib/shared-blackboard.js.map +1 -0
- package/dist/esm/lib/skill-composer.js +190 -0
- package/dist/esm/lib/skill-composer.js.map +1 -0
- package/dist/esm/lib/speculative-executor.js +107 -0
- package/dist/esm/lib/speculative-executor.js.map +1 -0
- package/dist/esm/lib/strategy-agent.js +626 -0
- package/dist/esm/lib/strategy-agent.js.map +1 -0
- package/dist/esm/lib/swarm-transport.js +307 -0
- package/dist/esm/lib/swarm-transport.js.map +1 -0
- package/dist/esm/lib/swarm-utils.js +510 -0
- package/dist/esm/lib/swarm-utils.js.map +1 -0
- package/dist/esm/lib/task-decomposer.js +272 -0
- package/dist/esm/lib/task-decomposer.js.map +1 -0
- package/dist/esm/lib/telemetry-provider.js +207 -0
- package/dist/esm/lib/telemetry-provider.js.map +1 -0
- package/dist/esm/lib/timeline-scrubber.js +173 -0
- package/dist/esm/lib/timeline-scrubber.js.map +1 -0
- package/dist/esm/lib/topology.js +591 -0
- package/dist/esm/lib/topology.js.map +1 -0
- package/dist/esm/lib/transport-agent.js +366 -0
- package/dist/esm/lib/transport-agent.js.map +1 -0
- package/dist/esm/lib/work-tree-dashboard.js +583 -0
- package/dist/esm/lib/work-tree-dashboard.js.map +1 -0
- package/dist/esm/lib/work-tree-ui.js +333 -0
- package/dist/esm/lib/work-tree-ui.js.map +1 -0
- package/dist/esm/lib/work-tree.js +480 -0
- package/dist/esm/lib/work-tree.js.map +1 -0
- package/dist/esm/run.js +144 -0
- package/dist/esm/run.js.map +1 -0
- package/dist/esm/security.js +1122 -0
- package/dist/esm/security.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp-transport-http.d.ts +203 -0
- package/dist/lib/mcp-transport-http.d.ts.map +1 -0
- package/dist/lib/mcp-transport-http.js +528 -0
- package/dist/lib/mcp-transport-http.js.map +1 -0
- package/dist/lib/phase-pipeline.d.ts +31 -0
- package/dist/lib/phase-pipeline.d.ts.map +1 -1
- package/dist/lib/phase-pipeline.js +93 -1
- package/dist/lib/phase-pipeline.js.map +1 -1
- package/dist/lib/semantic-search.d.ts +42 -6
- package/dist/lib/semantic-search.d.ts.map +1 -1
- package/dist/lib/semantic-search.js +87 -6
- package/dist/lib/semantic-search.js.map +1 -1
- package/package.json +24 -4
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Barnes-Hut QuadTree — Spatial indexing for O(n log n) force simulation
|
|
4
|
+
*
|
|
5
|
+
* Used by the topology dashboard to replace the naive O(n²) all-pairs
|
|
6
|
+
* repulsion with Barnes-Hut approximation. Also provides viewport queries
|
|
7
|
+
* for culling off-screen nodes.
|
|
8
|
+
*
|
|
9
|
+
* @module QuadTree
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.QuadTree = void 0;
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// QUADTREE NODE
|
|
16
|
+
// ============================================================================
|
|
17
|
+
const QT_CAPACITY = 8; // Points per leaf before subdividing
|
|
18
|
+
/**
|
|
19
|
+
* A QuadTree for 2D spatial indexing with Barnes-Hut mass summaries.
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const qt = new QuadTree({ x: 500, y: 400, halfW: 500, halfH: 400 });
|
|
24
|
+
* qt.insert({ id: 'a', x: 100, y: 200 });
|
|
25
|
+
* qt.insert({ id: 'b', x: 300, y: 150 });
|
|
26
|
+
*
|
|
27
|
+
* // Barnes-Hut force query (theta = 0.5)
|
|
28
|
+
* qt.forceOnPoint(100, 200, 0.5, (cx, cy, mass, dx, dy, distSq) => {
|
|
29
|
+
* // Apply repulsion force from (cx, cy) with given mass
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Viewport query
|
|
33
|
+
* const visible = qt.queryRange({ x: 250, y: 250, halfW: 250, halfH: 250 });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class QuadTree {
|
|
37
|
+
bounds;
|
|
38
|
+
points = [];
|
|
39
|
+
divided = false;
|
|
40
|
+
nw = null;
|
|
41
|
+
ne = null;
|
|
42
|
+
sw = null;
|
|
43
|
+
se = null;
|
|
44
|
+
mass = { count: 0, cx: 0, cy: 0 };
|
|
45
|
+
constructor(bounds) {
|
|
46
|
+
this.bounds = bounds;
|
|
47
|
+
}
|
|
48
|
+
// --------------------------------------------------------------------------
|
|
49
|
+
// INSERTION
|
|
50
|
+
// --------------------------------------------------------------------------
|
|
51
|
+
/**
|
|
52
|
+
* Insert a point into the tree.
|
|
53
|
+
* @returns true if inserted, false if out of bounds
|
|
54
|
+
*/
|
|
55
|
+
insert(point) {
|
|
56
|
+
if (!this.containsPoint(point.x, point.y))
|
|
57
|
+
return false;
|
|
58
|
+
// Update mass center incrementally
|
|
59
|
+
const prev = this.mass.count;
|
|
60
|
+
this.mass.cx = (this.mass.cx * prev + point.x) / (prev + 1);
|
|
61
|
+
this.mass.cy = (this.mass.cy * prev + point.y) / (prev + 1);
|
|
62
|
+
this.mass.count = prev + 1;
|
|
63
|
+
if (!this.divided && this.points.length < QT_CAPACITY) {
|
|
64
|
+
this.points.push(point);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (!this.divided) {
|
|
68
|
+
this.subdivide();
|
|
69
|
+
}
|
|
70
|
+
if (this.nw.insert(point))
|
|
71
|
+
return true;
|
|
72
|
+
if (this.ne.insert(point))
|
|
73
|
+
return true;
|
|
74
|
+
if (this.sw.insert(point))
|
|
75
|
+
return true;
|
|
76
|
+
if (this.se.insert(point))
|
|
77
|
+
return true;
|
|
78
|
+
// Shouldn't happen if containsPoint passed, but safety fallback
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build the tree from an array of points (faster than individual inserts).
|
|
83
|
+
*/
|
|
84
|
+
static build(points, bounds) {
|
|
85
|
+
const tree = new QuadTree(bounds);
|
|
86
|
+
for (const p of points) {
|
|
87
|
+
tree.insert(p);
|
|
88
|
+
}
|
|
89
|
+
return tree;
|
|
90
|
+
}
|
|
91
|
+
// --------------------------------------------------------------------------
|
|
92
|
+
// QUERIES
|
|
93
|
+
// --------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Find all points within a rectangular viewport.
|
|
96
|
+
*/
|
|
97
|
+
queryRange(range) {
|
|
98
|
+
const found = [];
|
|
99
|
+
this.queryRangeInto(range, found);
|
|
100
|
+
return found;
|
|
101
|
+
}
|
|
102
|
+
queryRangeInto(range, found) {
|
|
103
|
+
if (!this.intersects(range))
|
|
104
|
+
return;
|
|
105
|
+
for (const p of this.points) {
|
|
106
|
+
if (p.x >= range.x - range.halfW &&
|
|
107
|
+
p.x <= range.x + range.halfW &&
|
|
108
|
+
p.y >= range.y - range.halfH &&
|
|
109
|
+
p.y <= range.y + range.halfH) {
|
|
110
|
+
found.push(p);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (this.divided) {
|
|
114
|
+
this.nw.queryRangeInto(range, found);
|
|
115
|
+
this.ne.queryRangeInto(range, found);
|
|
116
|
+
this.sw.queryRangeInto(range, found);
|
|
117
|
+
this.se.queryRangeInto(range, found);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// --------------------------------------------------------------------------
|
|
121
|
+
// BARNES-HUT FORCE TRAVERSAL
|
|
122
|
+
// --------------------------------------------------------------------------
|
|
123
|
+
/**
|
|
124
|
+
* Traverse the tree with Barnes-Hut approximation for a single point.
|
|
125
|
+
*
|
|
126
|
+
* For each region, if the region is "far enough" (width/distance < theta),
|
|
127
|
+
* treat it as a point mass at the center of mass. Otherwise recurse.
|
|
128
|
+
*
|
|
129
|
+
* @param px - Query point x
|
|
130
|
+
* @param py - Query point y
|
|
131
|
+
* @param theta - Opening angle threshold (0.5 is common, higher = faster but less accurate)
|
|
132
|
+
* @param callback - Called for each mass interaction: (cx, cy, mass, dx, dy, distSq)
|
|
133
|
+
*/
|
|
134
|
+
forceOnPoint(px, py, theta, callback) {
|
|
135
|
+
if (this.mass.count === 0)
|
|
136
|
+
return;
|
|
137
|
+
const dx = this.mass.cx - px;
|
|
138
|
+
const dy = this.mass.cy - py;
|
|
139
|
+
const distSq = dx * dx + dy * dy;
|
|
140
|
+
// If this is a leaf with points, interact directly
|
|
141
|
+
if (!this.divided) {
|
|
142
|
+
if (distSq > 0.01) {
|
|
143
|
+
callback(this.mass.cx, this.mass.cy, this.mass.count, dx, dy, distSq);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// Barnes-Hut criterion: region width / distance < theta → approximate
|
|
148
|
+
const regionWidth = this.bounds.halfW * 2;
|
|
149
|
+
if (regionWidth * regionWidth < theta * theta * distSq) {
|
|
150
|
+
callback(this.mass.cx, this.mass.cy, this.mass.count, dx, dy, distSq);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Recurse into children
|
|
154
|
+
this.nw.forceOnPoint(px, py, theta, callback);
|
|
155
|
+
this.ne.forceOnPoint(px, py, theta, callback);
|
|
156
|
+
this.sw.forceOnPoint(px, py, theta, callback);
|
|
157
|
+
this.se.forceOnPoint(px, py, theta, callback);
|
|
158
|
+
}
|
|
159
|
+
// --------------------------------------------------------------------------
|
|
160
|
+
// ACCESSORS
|
|
161
|
+
// --------------------------------------------------------------------------
|
|
162
|
+
/** Total point count in this subtree */
|
|
163
|
+
get count() {
|
|
164
|
+
return this.mass.count;
|
|
165
|
+
}
|
|
166
|
+
/** The mass summary of this subtree */
|
|
167
|
+
getMass() {
|
|
168
|
+
return { ...this.mass };
|
|
169
|
+
}
|
|
170
|
+
/** The bounds of this node */
|
|
171
|
+
getBounds() {
|
|
172
|
+
return { ...this.bounds };
|
|
173
|
+
}
|
|
174
|
+
/** Whether this node has been subdivided */
|
|
175
|
+
get isSubdivided() {
|
|
176
|
+
return this.divided;
|
|
177
|
+
}
|
|
178
|
+
// --------------------------------------------------------------------------
|
|
179
|
+
// CLUSTERING SUPPORT
|
|
180
|
+
// --------------------------------------------------------------------------
|
|
181
|
+
/**
|
|
182
|
+
* Get cluster summaries at a given depth or size threshold.
|
|
183
|
+
* Returns groups of points that share a QuadTree cell below the given size.
|
|
184
|
+
*
|
|
185
|
+
* @param maxCellSize - Maximum cell width to stop recursing (in world units)
|
|
186
|
+
* @returns Array of clusters, each with center, count, and contained point ids
|
|
187
|
+
*/
|
|
188
|
+
getClusters(maxCellSize) {
|
|
189
|
+
const clusters = [];
|
|
190
|
+
this.collectClusters(maxCellSize, clusters);
|
|
191
|
+
return clusters;
|
|
192
|
+
}
|
|
193
|
+
collectClusters(maxCellSize, out) {
|
|
194
|
+
if (this.mass.count === 0)
|
|
195
|
+
return;
|
|
196
|
+
const cellSize = this.bounds.halfW * 2;
|
|
197
|
+
// If this cell is small enough OR is a leaf, emit as cluster
|
|
198
|
+
if (cellSize <= maxCellSize || !this.divided) {
|
|
199
|
+
const ids = this.collectAllIds();
|
|
200
|
+
if (ids.length > 0) {
|
|
201
|
+
out.push({
|
|
202
|
+
cx: this.mass.cx,
|
|
203
|
+
cy: this.mass.cy,
|
|
204
|
+
count: this.mass.count,
|
|
205
|
+
ids,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.nw.collectClusters(maxCellSize, out);
|
|
211
|
+
this.ne.collectClusters(maxCellSize, out);
|
|
212
|
+
this.sw.collectClusters(maxCellSize, out);
|
|
213
|
+
this.se.collectClusters(maxCellSize, out);
|
|
214
|
+
}
|
|
215
|
+
collectAllIds() {
|
|
216
|
+
const ids = [];
|
|
217
|
+
for (const p of this.points)
|
|
218
|
+
ids.push(p.id);
|
|
219
|
+
if (this.divided) {
|
|
220
|
+
ids.push(...this.nw.collectAllIds());
|
|
221
|
+
ids.push(...this.ne.collectAllIds());
|
|
222
|
+
ids.push(...this.sw.collectAllIds());
|
|
223
|
+
ids.push(...this.se.collectAllIds());
|
|
224
|
+
}
|
|
225
|
+
return ids;
|
|
226
|
+
}
|
|
227
|
+
// --------------------------------------------------------------------------
|
|
228
|
+
// INTERNALS
|
|
229
|
+
// --------------------------------------------------------------------------
|
|
230
|
+
subdivide() {
|
|
231
|
+
const { x, y, halfW, halfH } = this.bounds;
|
|
232
|
+
const qW = halfW / 2;
|
|
233
|
+
const qH = halfH / 2;
|
|
234
|
+
this.nw = new QuadTree({ x: x - qW, y: y - qH, halfW: qW, halfH: qH });
|
|
235
|
+
this.ne = new QuadTree({ x: x + qW, y: y - qH, halfW: qW, halfH: qH });
|
|
236
|
+
this.sw = new QuadTree({ x: x - qW, y: y + qH, halfW: qW, halfH: qH });
|
|
237
|
+
this.se = new QuadTree({ x: x + qW, y: y + qH, halfW: qW, halfH: qH });
|
|
238
|
+
// Re-insert existing points into children
|
|
239
|
+
for (const p of this.points) {
|
|
240
|
+
this.nw.insert(p) || this.ne.insert(p) || this.sw.insert(p) || this.se.insert(p);
|
|
241
|
+
}
|
|
242
|
+
this.points = [];
|
|
243
|
+
this.divided = true;
|
|
244
|
+
}
|
|
245
|
+
containsPoint(x, y) {
|
|
246
|
+
return (x >= this.bounds.x - this.bounds.halfW &&
|
|
247
|
+
x <= this.bounds.x + this.bounds.halfW &&
|
|
248
|
+
y >= this.bounds.y - this.bounds.halfH &&
|
|
249
|
+
y <= this.bounds.y + this.bounds.halfH);
|
|
250
|
+
}
|
|
251
|
+
intersects(range) {
|
|
252
|
+
return !(range.x - range.halfW > this.bounds.x + this.bounds.halfW ||
|
|
253
|
+
range.x + range.halfW < this.bounds.x - this.bounds.halfW ||
|
|
254
|
+
range.y - range.halfH > this.bounds.y + this.bounds.halfH ||
|
|
255
|
+
range.y + range.halfH < this.bounds.y - this.bounds.halfH);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
exports.QuadTree = QuadTree;
|
|
259
|
+
//# sourceMappingURL=quadtree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quadtree.js","sourceRoot":"","sources":["../../../lib/quadtree.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AA+BH,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,qCAAqC;AAE5D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,QAAQ;IACX,MAAM,CAAW;IACjB,MAAM,GAAc,EAAE,CAAC;IACvB,OAAO,GAAG,KAAK,CAAC;IAChB,EAAE,GAAoB,IAAI,CAAC;IAC3B,EAAE,GAAoB,IAAI,CAAC;IAC3B,EAAE,GAAoB,IAAI,CAAC;IAC3B,EAAE,GAAoB,IAAI,CAAC;IAC3B,IAAI,GAAW,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IAElD,YAAY,MAAgB;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAE7E;;;OAGG;IACH,MAAM,CAAC,KAAc;QACnB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAExD,mCAAmC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;QAE3B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;YACtD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;QAED,IAAI,IAAI,CAAC,EAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,EAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,EAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,EAAG,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAExC,gEAAgE;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,MAAiB,EAAE,MAAgB;QAC9C,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAClC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6EAA6E;IAC7E,UAAU;IACV,6EAA6E;IAE7E;;OAEG;IACH,UAAU,CAAC,KAAe;QACxB,MAAM,KAAK,GAAc,EAAE,CAAC;QAC5B,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,cAAc,CAAC,KAAe,EAAE,KAAgB;QACtD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO;QAEpC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,IACE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK;gBAC5B,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK;gBAC5B,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK;gBAC5B,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,EAC5B,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,EAAG,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,EAAG,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,EAAG,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,EAAG,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,6BAA6B;IAC7B,6EAA6E;IAE7E;;;;;;;;;;OAUG;IACH,YAAY,CACV,EAAU,EACV,EAAU,EACV,KAAa,EACb,QAAgG;QAEhG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO;QAElC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAEjC,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YACxE,CAAC;YACD,OAAO;QACT,CAAC;QAED,sEAAsE;QACtE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QAC1C,IAAI,WAAW,GAAG,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,EAAE,CAAC;YACvD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,wBAAwB;QACxB,IAAI,CAAC,EAAG,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAG,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAG,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAG,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAE7E,wCAAwC;IACxC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,uCAAuC;IACvC,OAAO;QACL,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,8BAA8B;IAC9B,SAAS;QACP,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,4CAA4C;IAC5C,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,6EAA6E;IAC7E,qBAAqB;IACrB,6EAA6E;IAE7E;;;;;;OAMG;IACH,WAAW,CAAC,WAAmB;QAC7B,MAAM,QAAQ,GAAoE,EAAE,CAAC;QACrF,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC5C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,eAAe,CACrB,WAAmB,EACnB,GAAoE;QAEpE,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO;QAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QAEvC,6DAA6D;QAC7D,IAAI,QAAQ,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnB,GAAG,CAAC,IAAI,CAAC;oBACP,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;oBAChB,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;oBAChB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;oBACtB,GAAG;iBACJ,CAAC,CAAC;YACL,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,EAAG,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAG,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAG,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAG,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,aAAa,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,aAAa,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,aAAa,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAErE,SAAS;QACf,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3C,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;QAErB,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAEvE,0CAA0C;QAC1C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAEO,aAAa,CAAC,CAAS,EAAE,CAAS;QACxC,OAAO,CACL,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACtC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACtC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACtC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CACvC,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,KAAe;QAChC,OAAO,CAAC,CACN,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACzD,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACzD,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK;YACzD,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAC1D,CAAC;IACJ,CAAC;CACF;AAxQD,4BAwQC"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Route Classifier — Short-Circuit Routing for Network-AI
|
|
4
|
+
*
|
|
5
|
+
* Classifies an incoming goal into one of three categories before any
|
|
6
|
+
* DAG planning occurs. Simple factual lookups are routed directly to a
|
|
7
|
+
* single agent, bypassing the Blackboard/locking layer entirely to save
|
|
8
|
+
* latency and token cost. Complex synthesis uses the full DAG pipeline.
|
|
9
|
+
* System failures are surfaced immediately.
|
|
10
|
+
*
|
|
11
|
+
* Zero external dependencies — the classifier function is pluggable so
|
|
12
|
+
* callers can use any model (Haiku, Llama-3-8B, rule-based heuristic, …).
|
|
13
|
+
*
|
|
14
|
+
* @module RouteClassifier
|
|
15
|
+
* @version 1.0.0
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.RouteClassifier = void 0;
|
|
19
|
+
exports.createHeuristicClassifier = createHeuristicClassifier;
|
|
20
|
+
exports.createLLMClassifier = createLLMClassifier;
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// RULE-BASED HEURISTIC CLASSIFIER (built-in, zero model cost)
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* A simple keyword / length heuristic classifier for when you don't want to
|
|
26
|
+
* spend tokens on a model call for every request.
|
|
27
|
+
*
|
|
28
|
+
* Treats goals of ≤ 15 words with question-like phrasing as FACTUAL_LOOKUP
|
|
29
|
+
* and everything else as COMPLEX_SYNTHESIS.
|
|
30
|
+
*/
|
|
31
|
+
function createHeuristicClassifier() {
|
|
32
|
+
const LOOKUP_STARTERS = [
|
|
33
|
+
'what is', 'what are', 'who is', 'who are', 'when is', 'when was',
|
|
34
|
+
'where is', 'where was', 'how many', 'how much', 'define ', 'list ',
|
|
35
|
+
'name ', 'tell me', 'give me', 'show me',
|
|
36
|
+
];
|
|
37
|
+
return async (goal) => {
|
|
38
|
+
const normalized = goal.trim().toLowerCase();
|
|
39
|
+
if (!normalized) {
|
|
40
|
+
return {
|
|
41
|
+
category: 'SYSTEM_FAILURE',
|
|
42
|
+
rationale: 'Goal is empty',
|
|
43
|
+
confidence: 1,
|
|
44
|
+
classifiedAt: Date.now(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const wordCount = normalized.split(/\s+/).length;
|
|
48
|
+
const isShort = wordCount <= 15;
|
|
49
|
+
const startsLikeQuestion = LOOKUP_STARTERS.some((s) => normalized.startsWith(s));
|
|
50
|
+
const endsWithQuestion = normalized.endsWith('?');
|
|
51
|
+
if (isShort && (startsLikeQuestion || endsWithQuestion)) {
|
|
52
|
+
return {
|
|
53
|
+
category: 'FACTUAL_LOOKUP',
|
|
54
|
+
rationale: `Short goal (${wordCount} words) with question-like phrasing.`,
|
|
55
|
+
confidence: 0.8,
|
|
56
|
+
classifiedAt: Date.now(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
category: 'COMPLEX_SYNTHESIS',
|
|
61
|
+
rationale: `Goal requires multi-step reasoning (${wordCount} words).`,
|
|
62
|
+
confidence: 0.75,
|
|
63
|
+
classifiedAt: Date.now(),
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a classifier backed by an LLM via the Network-AI executor API.
|
|
69
|
+
*
|
|
70
|
+
* @param executor - The executor function from the adapter system
|
|
71
|
+
* @param classifierAgentId - Agent ID for the fast classification model
|
|
72
|
+
*/
|
|
73
|
+
function createLLMClassifier(executor, classifierAgentId) {
|
|
74
|
+
return async (goal) => {
|
|
75
|
+
const prompt = [
|
|
76
|
+
'Classify the following goal into exactly one category:',
|
|
77
|
+
' FACTUAL_LOOKUP — simple factual question answerable in one step',
|
|
78
|
+
' COMPLEX_SYNTHESIS — requires multi-step research/reasoning/execution',
|
|
79
|
+
' SYSTEM_FAILURE — invalid, malformed, or unclassifiable input',
|
|
80
|
+
'',
|
|
81
|
+
`GOAL: ${goal}`,
|
|
82
|
+
'',
|
|
83
|
+
'Respond with ONLY valid JSON matching this schema:',
|
|
84
|
+
'{"category":"FACTUAL_LOOKUP|COMPLEX_SYNTHESIS|SYSTEM_FAILURE","rationale":"...","confidence":0.0-1.0}',
|
|
85
|
+
].join('\n');
|
|
86
|
+
try {
|
|
87
|
+
const result = await executor(classifierAgentId, { action: 'classify', params: { prompt } }, { agentId: classifierAgentId, taskId: `classify-${Date.now()}`, metadata: { type: 'route-classification' } });
|
|
88
|
+
if (!result.success || !result.data) {
|
|
89
|
+
return {
|
|
90
|
+
category: 'COMPLEX_SYNTHESIS',
|
|
91
|
+
rationale: 'Classifier returned no data — defaulting to COMPLEX_SYNTHESIS',
|
|
92
|
+
confidence: 0.5,
|
|
93
|
+
classifiedAt: Date.now(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Parse response
|
|
97
|
+
let parsed;
|
|
98
|
+
const raw = typeof result.data === 'string' ? result.data : JSON.stringify(result.data);
|
|
99
|
+
try {
|
|
100
|
+
// Strip markdown fences
|
|
101
|
+
const cleaned = raw.replace(/```[a-z]*\n?/g, '').replace(/```/g, '').trim();
|
|
102
|
+
const start = cleaned.indexOf('{');
|
|
103
|
+
const end = cleaned.lastIndexOf('}');
|
|
104
|
+
parsed = JSON.parse(cleaned.substring(start, end + 1));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return {
|
|
108
|
+
category: 'COMPLEX_SYNTHESIS',
|
|
109
|
+
rationale: 'Classifier response parse failed — defaulting to COMPLEX_SYNTHESIS',
|
|
110
|
+
confidence: 0.4,
|
|
111
|
+
classifiedAt: Date.now(),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const validCategories = ['FACTUAL_LOOKUP', 'COMPLEX_SYNTHESIS', 'SYSTEM_FAILURE'];
|
|
115
|
+
const category = validCategories.includes(parsed.category) ? parsed.category : 'COMPLEX_SYNTHESIS';
|
|
116
|
+
return {
|
|
117
|
+
category,
|
|
118
|
+
rationale: parsed.rationale ?? '',
|
|
119
|
+
confidence: typeof parsed.confidence === 'number' ? Math.min(1, Math.max(0, parsed.confidence)) : undefined,
|
|
120
|
+
classifiedAt: Date.now(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
return {
|
|
125
|
+
category: 'COMPLEX_SYNTHESIS',
|
|
126
|
+
rationale: `Classifier error (${err.message}) — defaulting to COMPLEX_SYNTHESIS`,
|
|
127
|
+
confidence: 0.3,
|
|
128
|
+
classifiedAt: Date.now(),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// ROUTE CLASSIFIER
|
|
135
|
+
// ============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* RouteClassifier evaluates a goal before DAG planning begins and decides
|
|
138
|
+
* whether to short-circuit to a single agent (FACTUAL_LOOKUP) or proceed
|
|
139
|
+
* with the full multi-agent pipeline (COMPLEX_SYNTHESIS).
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const classifier = new RouteClassifier(createHeuristicClassifier());
|
|
144
|
+
* const { category } = await classifier.classify('What is the capital of France?');
|
|
145
|
+
* // category === 'FACTUAL_LOOKUP'
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
class RouteClassifier {
|
|
149
|
+
classifierFn;
|
|
150
|
+
options;
|
|
151
|
+
constructor(classifierFn, options = {}) {
|
|
152
|
+
this.classifierFn = classifierFn;
|
|
153
|
+
this.options = options;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Classify a goal.
|
|
157
|
+
*/
|
|
158
|
+
async classify(goal) {
|
|
159
|
+
if (!goal || typeof goal !== 'string') {
|
|
160
|
+
return {
|
|
161
|
+
category: 'SYSTEM_FAILURE',
|
|
162
|
+
rationale: 'Goal must be a non-empty string',
|
|
163
|
+
confidence: 1,
|
|
164
|
+
classifiedAt: Date.now(),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return this.classifierFn(goal);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Classify a goal and, if FACTUAL_LOOKUP, short-circuit to a single agent.
|
|
171
|
+
*
|
|
172
|
+
* Returns the classification result and, when short-circuited, the agent's
|
|
173
|
+
* direct answer. The caller should check `result.shortCircuited` — if false,
|
|
174
|
+
* proceed with the normal DAG pipeline.
|
|
175
|
+
*
|
|
176
|
+
* @param goal - Natural language goal
|
|
177
|
+
* @param executor - Agent executor (required for FACTUAL_LOOKUP short-circuit)
|
|
178
|
+
* @param fallbackAgentId - Agent to call on FACTUAL_LOOKUP (overrides options.lookupAgentId)
|
|
179
|
+
*/
|
|
180
|
+
async route(goal, executor, fallbackAgentId) {
|
|
181
|
+
const classification = await this.classify(goal);
|
|
182
|
+
if (classification.category === 'SYSTEM_FAILURE') {
|
|
183
|
+
return {
|
|
184
|
+
classification,
|
|
185
|
+
shortCircuited: true,
|
|
186
|
+
error: `System failure: ${classification.rationale}`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (classification.category === 'FACTUAL_LOOKUP') {
|
|
190
|
+
const agentId = fallbackAgentId ?? this.options.lookupAgentId;
|
|
191
|
+
if (!executor || !agentId) {
|
|
192
|
+
// No executor configured — fall through to DAG pipeline
|
|
193
|
+
return { classification, shortCircuited: false };
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const result = await executor(agentId, { action: 'answer', params: { goal } }, { agentId, taskId: `lookup-${Date.now()}`, metadata: { type: 'factual-lookup' } });
|
|
197
|
+
return {
|
|
198
|
+
classification,
|
|
199
|
+
shortCircuited: true,
|
|
200
|
+
answer: result.data,
|
|
201
|
+
error: result.success ? undefined : result.error?.message,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
return {
|
|
206
|
+
classification,
|
|
207
|
+
shortCircuited: true,
|
|
208
|
+
error: err.message,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// COMPLEX_SYNTHESIS — proceed with DAG
|
|
213
|
+
return { classification, shortCircuited: false };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.RouteClassifier = RouteClassifier;
|
|
217
|
+
//# sourceMappingURL=route-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-classifier.js","sourceRoot":"","sources":["../../../lib/route-classifier.ts"],"names":[],"mappings":"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"}
|