import { d as getBrainNativeDb } from './sqlite-Dsbe0wec.js';
import './chunk-DDP5xfzh.js';
import 'node:module';
import './paths-2M_UxD_H.js';
import 'node:fs';
import 'node:path';
import 'node:os';
import 'node:events';
import 'node:diagnostics_channel';
import 'fs';
import 'events';
import 'util';
import 'path';
import 'assert';
import 'worker_threads';
import 'module';
import 'node:url';
import 'url';
import 'buffer';
import 'node:child_process';
import 'node:crypto';
import 'node:process';
import 'node:async_hooks';
import './dual-scope-db-ATrwq0LH.js';
import './indexes-aYlULWG3.js';
import './utils-BvHPJOVk.js';
import './conduit-Ca_OFWR_.js';
import './unique-constraint-BM-Apx1H.js';
import './memory-schema-Bi7cChwo.js';
import './agent-registry-BtE5uhMO.js';
import './nexus-sqlite2-DgTuv9BQ.js';
import './nexus-schema2-BEd-ol6e.js';
import './logger-ChCwlV5k.js';
import 'node:sqlite';
import './lock-BoHF25mx.js';
import './index-IVoIz4D5.js';
import 'constants';
import 'stream';

//#region ../core/dist/memory/surprisal-tree.js
/**
* RPTree — Random Projection Tree for hierarchical memory clustering
*
* Implements a simplified Random Projection Tree (RPTree) that partitions
* a set of observation embeddings into a hierarchical cluster structure.
* Each leaf node contains a group of semantically-similar observations.
*
* Algorithm:
*   1. Generate a random projection vector
*   2. Compute dot products of all embeddings with the projection
*   3. Split at the median (left = below, right = above)
*   4. Recurse until min_leaf_size or max_depth is reached
*
* Trees are rebuilt each dream cycle (brain_memory_trees table is truncated
* and repopulated). This is intentional — trees are a cache, not a source
* of truth.
*
* Persistence: tree nodes are written to brain_memory_trees. The leaf node
* id is written back to brain_observations.tree_id.
*
* @task T1146
* @epic T1146
*/
/** Maximum tree depth. Prevents infinite recursion on tiny datasets. */
var MAX_DEPTH = 8;
/** Minimum leaf size: stop splitting when a node has this many obs or fewer. */
var MIN_LEAF_SIZE = 3;
/** Embedding dimension. Matches CLEO brain embeddings (OpenAI/Anthropic = 1536 or 768). */
var DEFAULT_EMBEDDING_DIM = 1536;
/**
* Generate a random unit vector of dimension `dim` using Box-Muller transform.
*
* Uses Math.random() (uniform [0,1)) rather than raw randomBytes Float32 bit
* patterns — the previous implementation interpreted crypto byte sequences as
* Float32 values, which can produce NaN/Infinity components that propagate
* through dot products and corrupt the median split (T-spec-flake fix).
*/
function randomProjectionVector(dim) {
	const result = [];
	let norm = 0;
	for (let i = 0; i < dim; i += 2) {
		const u1 = Math.random() || 1e-300;
		const u2 = Math.random();
		const r = Math.sqrt(-2 * Math.log(u1));
		const theta = 2 * Math.PI * u2;
		const z0 = r * Math.cos(theta);
		const z1 = r * Math.sin(theta);
		result.push(z0);
		norm += z0 * z0;
		if (i + 1 < dim) {
			result.push(z1);
			norm += z1 * z1;
		}
	}
	const normSqrt = Math.sqrt(norm) || 1;
	return result.map((v) => v / normSqrt);
}
/** Dot product of two equal-length arrays. */
function dotProduct(a, b) {
	let sum = 0;
	const len = Math.min(a.length, b.length);
	for (let i = 0; i < len; i++) sum += (a[i] ?? 0) * (b[i] ?? 0);
	return sum;
}
/** Compute centroid (mean) of a set of embeddings. */
function computeCentroid(embeddings) {
	if (embeddings.length === 0) return null;
	const dim = embeddings[0]?.length ?? 0;
	const centroid = new Array(dim).fill(0);
	for (const emb of embeddings) for (let i = 0; i < dim; i++) centroid[i] = (centroid[i] ?? 0) + (emb[i] ?? 0);
	return centroid.map((v) => v / embeddings.length);
}
/**
* Recursively build an RPTree node for the given subset of observations.
*/
function buildNode(observations, depth, parentDbId, maxDepth, minLeafSize) {
	const embeddings = observations.map((o) => o.embedding);
	const centroid = computeCentroid(embeddings);
	if (observations.length <= minLeafSize || depth >= maxDepth) return {
		depth,
		leafIds: observations.map((o) => o.id),
		centroid,
		parentDbId,
		children: []
	};
	const projVector = randomProjectionVector(embeddings[0]?.length ?? DEFAULT_EMBEDDING_DIM);
	const projected = observations.map((obs) => ({
		obs,
		proj: dotProduct(obs.embedding, projVector)
	}));
	const projValues = projected.map((p) => p.proj).sort((a, b) => a - b);
	const median = projValues[Math.floor(projValues.length / 2)] ?? 0;
	const left = projected.filter((p) => p.proj <= median).map((p) => p.obs);
	const right = projected.filter((p) => p.proj > median).map((p) => p.obs);
	if (left.length === 0 || right.length === 0) return {
		depth,
		leafIds: observations.map((o) => o.id),
		centroid,
		parentDbId,
		children: []
	};
	return {
		depth,
		leafIds: [],
		centroid,
		parentDbId,
		children: [buildNode(left, depth + 1, null, maxDepth, minLeafSize), buildNode(right, depth + 1, null, maxDepth, minLeafSize)]
	};
}
/**
* Persist a tree node to the database and return its assigned id.
* Recursively persists children, updating their parentDbId.
*/
function persistNode(node, nativeDb, parentDbId) {
	const centroidJson = node.centroid ? JSON.stringify(node.centroid) : null;
	const leafIdsJson = JSON.stringify(node.leafIds);
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const result = nativeDb.prepare(`INSERT INTO brain_memory_trees (depth, leaf_ids, centroid, parent_id, created_at)
       VALUES (?, ?, ?, ?, ?)`).run(node.depth, leafIdsJson, centroidJson, parentDbId, now);
	const nodeId = Number(result.lastInsertRowid);
	for (const child of node.children) persistNode(child, nativeDb, nodeId);
	return nodeId;
}
/**
* Collect all leaf nodes and their observation IDs for brain_observations update.
*/
function collectLeafAssignments(node, nodeId, nativeDb, assignments) {
	if (node.leafIds.length > 0) for (const obsId of node.leafIds) assignments.set(obsId, nodeId);
	if (node.children.length > 0) {
		const children = nativeDb.prepare(`SELECT id, leaf_ids FROM brain_memory_trees WHERE parent_id = ?`).all(nodeId);
		for (const childRow of children) {
			const childLeafIds = JSON.parse(childRow.leaf_ids);
			if (childLeafIds.length > 0) for (const obsId of childLeafIds) assignments.set(obsId, childRow.id);
		}
	}
}
/**
* Build a Random Projection Tree from a set of observations and persist it
* to brain_memory_trees. Updates brain_observations.tree_id for all leaf members.
*
* Truncates existing brain_memory_trees rows before writing (trees are
* rebuilt each dream cycle from scratch).
*
* Requires at least 2 observations. Returns early with zero counts if fewer
* are provided.
*
* @param observations - Set of observations with embeddings to cluster.
* @param options      - Depth/leaf config, db injection for tests.
* @returns Build result with node/assignment counts.
*
* @task T1146
*/
function buildSurprisalTree(observations, options = {}) {
	const { maxDepth = MAX_DEPTH, minLeafSize = MIN_LEAF_SIZE, db: injectedDb } = options;
	const result = {
		nodesWritten: 0,
		obsAssigned: 0,
		actualMaxDepth: 0
	};
	const eligible = observations.filter((o) => o.embedding.length > 0);
	if (eligible.length < 2) return result;
	const nativeDb = injectedDb !== void 0 ? injectedDb : getBrainNativeDb();
	if (!nativeDb) {
		console.warn("[surprisal-tree] No database available; skipping tree build.");
		return result;
	}
	try {
		nativeDb.exec("DELETE FROM brain_memory_trees");
		const rootNode = buildNode(eligible, 0, null, maxDepth, minLeafSize);
		const rootId = persistNode(rootNode, nativeDb, null);
		result.nodesWritten = nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_memory_trees").get()?.cnt ?? 0;
		result.actualMaxDepth = nativeDb.prepare("SELECT MAX(depth) AS maxd FROM brain_memory_trees").get()?.maxd ?? 0;
		const assignments = /* @__PURE__ */ new Map();
		collectLeafAssignments(rootNode, rootId, nativeDb, assignments);
		const leafRows = nativeDb.prepare(`SELECT id, leaf_ids FROM brain_memory_trees WHERE leaf_ids != '[]'`).all();
		for (const leafRow of leafRows) {
			const leafIds = JSON.parse(leafRow.leaf_ids);
			for (const obsId of leafIds) assignments.set(obsId, leafRow.id);
		}
		for (const [obsId, treeNodeId] of assignments) {
			nativeDb.prepare("UPDATE brain_observations SET tree_id = ? WHERE id = ?").run(treeNodeId, obsId);
			result.obsAssigned++;
		}
		return result;
	} catch (err) {
		console.warn("[surprisal-tree] Error building tree:", err);
		return result;
	}
}

export { buildSurprisalTree };
//# sourceMappingURL=surprisal-tree-CApfzK6D.js.map
