trellis
Version:
Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications
1,096 lines (1,085 loc) • 32.2 kB
JavaScript
import {
__esm,
__export,
__require
} from "./chunk-2ESYSVXG.js";
// src/embeddings/types.ts
var DEFAULT_MODEL_CONFIG;
var init_types = __esm({
"src/embeddings/types.ts"() {
"use strict";
DEFAULT_MODEL_CONFIG = {
modelName: "Xenova/all-MiniLM-L6-v2",
dimension: 384
};
}
});
// src/embeddings/model.ts
async function importTransformers() {
try {
return await import("@huggingface/transformers");
} catch {
try {
return await import("@xenova/transformers");
} catch {
throw new Error(
"No transformers library found. Install @huggingface/transformers (recommended) or @xenova/transformers."
);
}
}
}
async function loadModel(config = DEFAULT_MODEL_CONFIG) {
if (pipeline) return pipeline;
if (!loadPromise) {
loadPromise = (async () => {
const { pipeline: createPipeline } = await importTransformers();
const opts = {};
if (config.cacheDir) {
opts.cache_dir = config.cacheDir;
}
pipeline = await createPipeline(
"feature-extraction",
config.modelName,
opts
);
return pipeline;
})();
}
return loadPromise;
}
async function embed(text, config = DEFAULT_MODEL_CONFIG) {
const pipe = await loadModel(config);
const output = await pipe(text, { pooling: "mean", normalize: true });
return new Float32Array(output.data);
}
async function embedBatch(texts, config = DEFAULT_MODEL_CONFIG) {
if (texts.length === 0) return [];
const pipe = await loadModel(config);
const results = [];
const batchSize = 32;
for (let i = 0; i < texts.length; i += batchSize) {
const batch = texts.slice(i, i + batchSize);
for (const text of batch) {
const output = await pipe(text, { pooling: "mean", normalize: true });
results.push(new Float32Array(output.data));
}
}
return results;
}
function resetModel() {
pipeline = null;
loadPromise = null;
}
var pipeline, loadPromise;
var init_model = __esm({
"src/embeddings/model.ts"() {
"use strict";
init_types();
pipeline = null;
loadPromise = null;
}
});
// src/embeddings/store.ts
function rowToChunkMeta(row) {
return {
id: row.id,
entityId: row.entity_id,
content: row.content,
chunkType: row.chunk_type,
filePath: row.file_path ?? void 0,
updatedAt: row.updated_at
};
}
function cosineSimilarity(a, b) {
if (a.length !== b.length) return 0;
let dot = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
const denom = Math.sqrt(normA) * Math.sqrt(normB);
return denom === 0 ? 0 : dot / denom;
}
var SCHEMA_SQL, VectorStore;
var init_store = __esm({
"src/embeddings/store.ts"() {
"use strict";
SCHEMA_SQL = `
CREATE TABLE IF NOT EXISTS chunks (
id TEXT PRIMARY KEY,
entity_id TEXT NOT NULL,
content TEXT NOT NULL,
chunk_type TEXT NOT NULL,
file_path TEXT,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS vectors (
id TEXT PRIMARY KEY,
embedding BLOB NOT NULL,
FOREIGN KEY (id) REFERENCES chunks(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_chunks_entity ON chunks(entity_id);
CREATE INDEX IF NOT EXISTS idx_chunks_type ON chunks(chunk_type);
CREATE INDEX IF NOT EXISTS idx_chunks_file ON chunks(file_path);
`;
VectorStore = class _VectorStore {
constructor(dbPath) {
this.dbPath = dbPath;
}
db;
stmts;
writes = 0;
/**
* Async factory — sql.js WASM init is async, but after bootstrap the store
* exposes a synchronous-style public API.
*/
static async create(dbPath) {
const store = new _VectorStore(dbPath);
await store.bootstrap();
return store;
}
async bootstrap() {
let initSqlJs;
try {
const mod = await import("sql.js");
initSqlJs = mod.default ?? mod;
} catch {
throw new Error(
'VectorStore requires the optional dependency "sql.js". Install it: npm install sql.js'
);
}
let sqljsDistDir = null;
if (typeof window === "undefined") {
try {
const moduleMod = await import("module");
const pathMod = await import("path");
const req = moduleMod.createRequire(import.meta.url);
const sqlJsEntry = req.resolve("sql.js");
sqljsDistDir = pathMod.dirname(sqlJsEntry);
} catch {
sqljsDistDir = null;
}
}
const SQL = await initSqlJs({
locateFile: (file) => {
if (typeof window !== "undefined") return `/sql-wasm/${file}`;
if (sqljsDistDir) return `${sqljsDistDir}/${file}`;
return file;
}
});
const existing = this.loadFromDisk();
this.db = existing ? new SQL.Database(existing) : new SQL.Database();
this.db.run("PRAGMA foreign_keys = ON;");
this.db.run(SCHEMA_SQL);
this.prepareStatements();
}
loadFromDisk() {
if (this.dbPath === ":memory:") return null;
try {
const fs = __require("fs");
if (!fs.existsSync(this.dbPath)) return null;
return new Uint8Array(fs.readFileSync(this.dbPath));
} catch {
return null;
}
}
flushToDisk() {
if (this.dbPath === ":memory:") return;
try {
const fs = __require("fs");
const path = __require("path");
const data = this.db.export();
this.prepareStatements();
fs.mkdirSync(path.dirname(this.dbPath), { recursive: true });
const tmp = `${this.dbPath}.tmp`;
fs.writeFileSync(tmp, Buffer.from(data));
fs.renameSync(tmp, this.dbPath);
} catch {
}
}
prepareStatements() {
this.stmts = {
upsertChunk: this.db.prepare(`
INSERT OR REPLACE INTO chunks (id, entity_id, content, chunk_type, file_path, updated_at)
VALUES ($id, $entityId, $content, $chunkType, $filePath, $updatedAt)
`),
upsertVector: this.db.prepare(`
INSERT OR REPLACE INTO vectors (id, embedding)
VALUES ($id, $embedding)
`),
deleteVector: this.db.prepare("DELETE FROM vectors WHERE id = $id"),
deleteChunk: this.db.prepare("DELETE FROM chunks WHERE id = $id"),
getChunkById: this.db.prepare("SELECT * FROM chunks WHERE id = $id"),
getChunkIdsByEntity: this.db.prepare(
"SELECT id FROM chunks WHERE entity_id = $entityId"
),
getChunkIdsByFile: this.db.prepare(
"SELECT id FROM chunks WHERE file_path = $filePath"
),
count: this.db.prepare("SELECT COUNT(*) AS cnt FROM chunks"),
countByType: this.db.prepare(
"SELECT chunk_type, COUNT(*) AS cnt FROM chunks GROUP BY chunk_type"
)
};
}
/**
* Insert or update a chunk with its embedding vector.
*/
upsert(record) {
const embeddingBlob = new Uint8Array(record.embedding.buffer);
this.db.run("BEGIN");
try {
this.stmts.upsertChunk.run({
$id: record.id,
$entityId: record.entityId,
$content: record.content,
$chunkType: record.chunkType,
$filePath: record.filePath ?? null,
$updatedAt: record.updatedAt
});
this.stmts.upsertChunk.reset();
this.stmts.upsertVector.run({
$id: record.id,
$embedding: embeddingBlob
});
this.stmts.upsertVector.reset();
this.db.run("COMMIT");
} catch (e) {
this.db.run("ROLLBACK");
throw e;
}
this.tickFlush();
}
/**
* Batch upsert multiple records.
*/
upsertBatch(records) {
if (records.length === 0) return;
this.db.run("BEGIN");
try {
for (const record of records) {
const embeddingBlob = new Uint8Array(record.embedding.buffer);
this.stmts.upsertChunk.run({
$id: record.id,
$entityId: record.entityId,
$content: record.content,
$chunkType: record.chunkType,
$filePath: record.filePath ?? null,
$updatedAt: record.updatedAt
});
this.stmts.upsertChunk.reset();
this.stmts.upsertVector.run({
$id: record.id,
$embedding: embeddingBlob
});
this.stmts.upsertVector.reset();
}
this.db.run("COMMIT");
} catch (e) {
this.db.run("ROLLBACK");
throw e;
}
this.tickFlush();
}
/**
* Delete a chunk and its vector by ID.
*/
delete(id) {
this.stmts.deleteVector.run({ $id: id });
this.stmts.deleteVector.reset();
this.stmts.deleteChunk.run({ $id: id });
this.stmts.deleteChunk.reset();
this.tickFlush();
}
/**
* Delete all chunks for an entity.
*/
deleteByEntity(entityId) {
const ids = this.runAll(this.stmts.getChunkIdsByEntity, {
$entityId: entityId
}).map((r) => r.id);
if (ids.length === 0) return;
this.db.run("BEGIN");
try {
for (const id of ids) {
this.stmts.deleteVector.run({ $id: id });
this.stmts.deleteVector.reset();
this.stmts.deleteChunk.run({ $id: id });
this.stmts.deleteChunk.reset();
}
this.db.run("COMMIT");
} catch (e) {
this.db.run("ROLLBACK");
throw e;
}
this.tickFlush();
}
/**
* Delete all chunks associated with a file path.
*/
deleteByFile(filePath) {
const ids = this.runAll(this.stmts.getChunkIdsByFile, {
$filePath: filePath
}).map((r) => r.id);
if (ids.length === 0) return;
this.db.run("BEGIN");
try {
for (const id of ids) {
this.stmts.deleteVector.run({ $id: id });
this.stmts.deleteVector.reset();
this.stmts.deleteChunk.run({ $id: id });
this.stmts.deleteChunk.reset();
}
this.db.run("COMMIT");
} catch (e) {
this.db.run("ROLLBACK");
throw e;
}
this.tickFlush();
}
/**
* Get a chunk by ID (without vector).
*/
getChunk(id) {
const row = this.runOne(this.stmts.getChunkById, { $id: id });
return row ? rowToChunkMeta(row) : null;
}
/**
* Search for chunks similar to the query vector.
* Uses brute-force cosine similarity scan.
*/
search(queryVector, opts = {}) {
const limit = opts.limit ?? 10;
const minScore = opts.minScore ?? 0;
const conditions = [];
const params = {};
if (opts.types && opts.types.length > 0) {
const placeholders = opts.types.map((_, i) => `$type${i}`).join(", ");
conditions.push(`c.chunk_type IN (${placeholders})`);
opts.types.forEach((t, i) => {
params[`$type${i}`] = t;
});
}
if (opts.filePrefix) {
conditions.push("c.file_path LIKE $filePrefix");
params.$filePrefix = `${opts.filePrefix}%`;
}
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
const sql = `
SELECT c.id, c.entity_id, c.content, c.chunk_type, c.file_path, c.updated_at,
v.embedding
FROM chunks c
JOIN vectors v ON c.id = v.id
${where}
`;
const stmt = this.db.prepare(sql);
const rows = this.runAll(stmt, params);
stmt.free();
const scored = [];
for (const row of rows) {
const embeddingBytes = row.embedding;
const ownedBuf = embeddingBytes.buffer.slice(
embeddingBytes.byteOffset,
embeddingBytes.byteOffset + embeddingBytes.byteLength
);
const storedVec = new Float32Array(ownedBuf);
const score = cosineSimilarity(queryVector, storedVec);
if (score >= minScore) {
scored.push({ chunk: rowToChunkMeta(row), score });
}
}
scored.sort((a, b) => b.score - a.score);
return scored.slice(0, limit);
}
/**
* Get total count of chunks in the store.
*/
count() {
const row = this.runOne(this.stmts.count);
return Number(row?.cnt ?? 0);
}
/**
* Get count by chunk type.
*/
countByType() {
const rows = this.runAll(this.stmts.countByType);
const result = {};
for (const row of rows) {
result[row.chunk_type] = row.cnt;
}
return result;
}
/**
* Clear all data from the store.
*/
clear() {
this.db.run("DELETE FROM vectors");
this.db.run("DELETE FROM chunks");
this.tickFlush();
}
/**
* Force a write of the in-memory DB image to disk.
*/
flush() {
this.flushToDisk();
}
/**
* Close the database connection.
*/
close() {
try {
this.flushToDisk();
} finally {
for (const s of Object.values(this.stmts ?? {})) s?.free?.();
this.db?.close?.();
}
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
runAll(stmt, params = {}) {
stmt.bind(params);
const rows = [];
while (stmt.step()) rows.push(stmt.getAsObject());
stmt.reset();
return rows;
}
runOne(stmt, params = {}) {
stmt.bind(params);
const has = stmt.step();
const row = has ? stmt.getAsObject() : void 0;
stmt.reset();
return row;
}
tickFlush() {
if (++this.writes % 50 === 0) this.flushToDisk();
}
};
}
});
// src/embeddings/chunker.ts
function chunkIssue(issue) {
const now = (/* @__PURE__ */ new Date()).toISOString();
const chunks = [];
if (issue.title) {
chunks.push({
id: `issue:${issue.id}:title`,
entityId: `issue:${issue.id}`,
content: issue.title,
chunkType: "issue_title",
updatedAt: now
});
}
if (issue.description) {
chunks.push({
id: `issue:${issue.id}:desc`,
entityId: `issue:${issue.id}`,
content: issue.description,
chunkType: "issue_desc",
updatedAt: now
});
}
return chunks;
}
function chunkDecision(decision) {
const parts = [];
parts.push(`Decision ${decision.id}: ${decision.toolName}`);
if (decision.rationale) parts.push(`Rationale: ${decision.rationale}`);
if (decision.context) parts.push(`Context: ${decision.context}`);
if (decision.outputSummary) parts.push(`Output: ${decision.outputSummary}`);
const content = parts.join("\n");
if (!content.trim()) return [];
return [
{
id: `decision:${decision.id}:rationale`,
entityId: `decision:${decision.id}`,
content,
chunkType: "decision_rationale",
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
}
];
}
function chunkMilestone(milestone) {
if (!milestone.message) return [];
return [
{
id: `milestone:${milestone.id}:msg`,
entityId: `milestone:${milestone.id}`,
content: milestone.message,
chunkType: "milestone_msg",
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
}
];
}
function chunkMarkdown(filePath, content) {
if (!content.trim()) return [];
const entityId = `file:${filePath}`;
const now = (/* @__PURE__ */ new Date()).toISOString();
const sections = splitByHeadings(content);
const chunks = [];
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
if (!section.text.trim()) continue;
if (section.text.length <= MAX_CHUNK_CHARS) {
chunks.push({
id: `${entityId}:section:${i}`,
entityId,
content: section.text,
chunkType: "markdown",
filePath,
updatedAt: now
});
} else {
const windows = slidingWindow(section.text);
for (let w = 0; w < windows.length; w++) {
chunks.push({
id: `${entityId}:section:${i}:w${w}`,
entityId,
content: windows[w],
chunkType: "markdown",
filePath,
updatedAt: now
});
}
}
}
return chunks;
}
function chunkCodeEntities(filePath, declarations) {
const now = (/* @__PURE__ */ new Date()).toISOString();
const chunks = [];
for (const decl of declarations) {
const parts = [];
if (decl.docComment) parts.push(decl.docComment);
parts.push(`${decl.kind} ${decl.name}`);
parts.push(decl.signature);
const content = parts.join("\n").slice(0, MAX_CHUNK_CHARS);
chunks.push({
id: `symbol:${filePath}#${decl.name}`,
entityId: `symbol:${filePath}#${decl.name}`,
content,
chunkType: "code_entity",
filePath,
updatedAt: now
});
}
return chunks;
}
function chunkDocComments(filePath, comments) {
if (comments.length === 0) return [];
const entityId = `file:${filePath}`;
const now = (/* @__PURE__ */ new Date()).toISOString();
const chunks = [];
for (let i = 0; i < comments.length; i++) {
const comment = comments[i];
if (!comment.text.trim()) continue;
chunks.push({
id: `${entityId}:doc:${i}`,
entityId,
content: comment.text.slice(0, MAX_CHUNK_CHARS),
chunkType: "doc_comment",
filePath,
updatedAt: now
});
}
return chunks;
}
function chunkSummary(filePath, content) {
if (!content.trim()) return [];
const entityId = `file:${filePath}`;
const now = (/* @__PURE__ */ new Date()).toISOString();
if (content.length <= MAX_CHUNK_CHARS) {
return [
{
id: `${entityId}:summary`,
entityId,
content,
chunkType: "summary_md",
filePath,
updatedAt: now
}
];
}
return chunkMarkdown(filePath, content).map((c) => ({
...c,
chunkType: "summary_md"
}));
}
function chunkFile(filePath, content) {
if (!content.trim()) return [];
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
if (filePath.endsWith("summary.md")) {
return chunkSummary(filePath, content);
}
if (ext === "md") {
return chunkMarkdown(filePath, content);
}
return [];
}
function splitByHeadings(content) {
const lines = content.split("\n");
const sections = [];
let currentSection = { text: "" };
for (const line of lines) {
if (/^#{1,3}\s/.test(line)) {
if (currentSection.text.trim()) {
sections.push(currentSection);
}
currentSection = { heading: line, text: line + "\n" };
} else {
currentSection.text += line + "\n";
}
}
if (currentSection.text.trim()) {
sections.push(currentSection);
}
return sections;
}
function slidingWindow(text) {
const windows = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + MAX_CHUNK_CHARS, text.length);
windows.push(text.slice(start, end));
if (end >= text.length) break;
start += MAX_CHUNK_CHARS - OVERLAP_CHARS;
}
return windows;
}
var MAX_CHUNK_CHARS, OVERLAP_CHARS;
var init_chunker = __esm({
"src/embeddings/chunker.ts"() {
"use strict";
MAX_CHUNK_CHARS = 512;
OVERLAP_CHARS = 64;
}
});
// src/embeddings/search.ts
import { join } from "path";
import { readFileSync, existsSync } from "fs";
var EmbeddingManager;
var init_search = __esm({
"src/embeddings/search.ts"() {
"use strict";
init_store();
init_model();
init_chunker();
EmbeddingManager = class _EmbeddingManager {
store;
embedFn;
constructor(store, embedFn) {
this.store = store;
this.embedFn = embedFn;
}
static async create(dbPath, embedFn) {
const store = await VectorStore.create(dbPath);
return new _EmbeddingManager(store, embedFn ?? embed);
}
/**
* Full reindex: clear store, re-chunk all entities, embed, and insert.
*/
async reindex(engine) {
this.store.clear();
const allChunks = [];
const issues = engine.listIssues();
for (const issue of issues) {
allChunks.push(...chunkIssue(issue));
}
const milestones = engine.listMilestones();
for (const ms of milestones) {
allChunks.push(...chunkMilestone(ms));
}
if (engine.queryDecisions) {
const decisions = engine.queryDecisions();
for (const dec of decisions) {
allChunks.push(...chunkDecision(dec));
}
}
const rootPath = engine.getRootPath();
const trackedFiles = engine.trackedFiles();
for (const tf of trackedFiles) {
try {
const absPath = join(rootPath, tf.path);
if (!existsSync(absPath)) continue;
const content = readFileSync(absPath, "utf-8");
allChunks.push(...chunkFile(tf.path, content));
} catch {
}
}
if (engine.parseFile) {
for (const tf of trackedFiles) {
const ext = tf.path.split(".").pop()?.toLowerCase() ?? "";
if (![
"ts",
"js",
"tsx",
"jsx",
"py",
"go",
"rs",
"rb",
"java",
"cs"
].includes(ext)) {
continue;
}
try {
const parsed = engine.parseFile(tf.path);
if (parsed && Array.isArray(parsed.entities)) {
const declarations = parsed.entities.map((e) => ({
id: e.id ?? e.name,
name: e.name,
kind: e.kind,
signature: e.signature ?? e.rawText?.split("\n")[0] ?? "",
docComment: e.docComment
}));
allChunks.push(...chunkCodeEntities(tf.path, declarations));
}
} catch {
}
}
}
const records = [];
for (const chunk of allChunks) {
try {
const vector = await this.embedFn(chunk.content);
records.push({ ...chunk, embedding: vector });
} catch {
}
}
this.store.upsertBatch(records);
return { chunks: records.length };
}
/**
* Incrementally index a single file (on file change).
*/
async indexFile(filePath, content, engine) {
this.store.deleteByFile(filePath);
const chunks = chunkFile(filePath, content);
if (engine?.parseFile) {
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
if ([
"ts",
"js",
"tsx",
"jsx",
"py",
"go",
"rs",
"rb",
"java",
"cs"
].includes(ext)) {
try {
const parsed = engine.parseFile(filePath);
if (parsed && Array.isArray(parsed.entities)) {
const declarations = parsed.entities.map((e) => ({
id: e.id ?? e.name,
name: e.name,
kind: e.kind,
signature: e.signature ?? e.rawText?.split("\n")[0] ?? "",
docComment: e.docComment
}));
chunks.push(...chunkCodeEntities(filePath, declarations));
}
} catch {
}
}
}
const records = [];
for (const chunk of chunks) {
try {
const vector = await this.embedFn(chunk.content);
records.push({ ...chunk, embedding: vector });
} catch {
}
}
if (records.length > 0) {
this.store.upsertBatch(records);
}
return records.length;
}
/**
* Index an issue (on create/update).
*/
async indexIssue(issue) {
this.store.deleteByEntity(`issue:${issue.id}`);
const chunks = chunkIssue(issue);
const records = [];
for (const chunk of chunks) {
try {
const vector = await this.embedFn(chunk.content);
records.push({ ...chunk, embedding: vector });
} catch {
}
}
if (records.length > 0) {
this.store.upsertBatch(records);
}
return records.length;
}
/**
* Index a milestone (on create).
*/
async indexMilestone(milestone) {
this.store.deleteByEntity(`milestone:${milestone.id}`);
const chunks = chunkMilestone(milestone);
const records = [];
for (const chunk of chunks) {
try {
const vector = await this.embedFn(chunk.content);
records.push({ ...chunk, embedding: vector });
} catch {
}
}
if (records.length > 0) {
this.store.upsertBatch(records);
}
return records.length;
}
/**
* Semantic search: embed query → vector search → ranked results.
*/
async search(query, opts) {
const queryVector = await this.embedFn(query);
return this.store.search(queryVector, opts);
}
/**
* Remove all data for a file.
*/
removeFile(filePath) {
this.store.deleteByFile(filePath);
}
/**
* Get store statistics.
*/
stats() {
return {
total: this.store.count(),
byType: this.store.countByType()
};
}
/**
* Close the store.
*/
close() {
this.store.close();
}
};
}
});
// src/embeddings/auto-embed.ts
function entitySummaryText(entityId, facts, links) {
const type = facts.find((f) => f.a === "type")?.v ?? "Entity";
const name = facts.find((f) => f.a === "name" || f.a === "title")?.v ?? entityId;
const parts = [`${type}: ${name} (${entityId})`];
const attrs = facts.filter(
(f) => !["type", "name", "title", "createdAt", "updatedAt"].includes(f.a)
);
if (attrs.length > 0) {
parts.push(attrs.map((f) => ` ${f.a} = ${f.v}`).join("\n"));
}
if (links.length > 0) {
parts.push("Relations:");
parts.push(links.map((l) => ` ${l.a} \u2192 ${l.e2}`).join("\n"));
}
return parts.join("\n");
}
async function createAutoEmbedMiddleware(options) {
const store = await VectorStore.create(options.dbPath);
const embedFn = options.embedFn ?? embed;
const embedIndividual = options.embedIndividualFacts ?? false;
return {
name: "auto-embed",
handleOp: async (op, ctx, next) => {
await next(op, ctx);
try {
await _processOp(op, store, embedFn, embedIndividual);
} catch {
}
},
close: () => {
store.close();
}
};
}
async function _processOp(op, store, embedFn, embedIndividual) {
const now = (/* @__PURE__ */ new Date()).toISOString();
const entityIds = /* @__PURE__ */ new Set();
if (op.facts) for (const f of op.facts) entityIds.add(f.e);
if (op.links)
for (const l of op.links) {
entityIds.add(l.e1);
entityIds.add(l.e2);
}
if (op.deleteFacts) for (const f of op.deleteFacts) entityIds.add(f.e);
if (op.deleteLinks)
for (const l of op.deleteLinks) {
entityIds.add(l.e1);
entityIds.add(l.e2);
}
let mutated = false;
if (op.deleteFacts || op.deleteLinks) {
for (const eid of entityIds) {
store.deleteByEntity(eid);
}
mutated = true;
}
if (op.facts && op.facts.length > 0) {
const factsByEntity = /* @__PURE__ */ new Map();
for (const f of op.facts) {
const existing = factsByEntity.get(f.e) ?? [];
existing.push(f);
factsByEntity.set(f.e, existing);
}
const linksByEntity = /* @__PURE__ */ new Map();
if (op.links) {
for (const l of op.links) {
const existing = linksByEntity.get(l.e1) ?? [];
existing.push(l);
linksByEntity.set(l.e1, existing);
}
}
const records = [];
for (const [eid, facts] of factsByEntity) {
const links = linksByEntity.get(eid) ?? [];
const summaryText = entitySummaryText(eid, facts, links);
if (summaryText.trim()) {
try {
const vector = await embedFn(summaryText);
records.push({
id: `entity:${eid}:summary`,
entityId: eid,
content: summaryText,
chunkType: "summary_md",
updatedAt: now,
embedding: vector
});
} catch {
}
}
if (embedIndividual) {
for (const fact of facts) {
if (["type", "createdAt", "updatedAt"].includes(fact.a)) continue;
const text = `${fact.a}: ${fact.v}`;
try {
const vector = await embedFn(text);
records.push({
id: `entity:${eid}:fact:${fact.a}`,
entityId: eid,
content: text,
chunkType: "doc_comment",
updatedAt: now,
embedding: vector
});
} catch {
}
}
}
}
if (records.length > 0) {
store.upsertBatch(records);
mutated = true;
}
}
if (mutated) {
store.flush();
}
}
async function buildRAGContext(query, vectorStore, embedFn = embed, options) {
const maxChunks = options?.maxChunks ?? 10;
const maxTokens = options?.maxTokens ?? 4e3;
const minScore = options?.minScore ?? 0.1;
const queryVector = await embedFn(query);
const results = vectorStore.search(queryVector, {
limit: maxChunks * 2,
minScore
});
const chunks = [];
let totalChars = 0;
for (const r of results) {
if (chunks.length >= maxChunks) break;
if (totalChars + r.chunk.content.length > maxTokens * 4) break;
chunks.push({
content: r.chunk.content,
entityId: r.chunk.entityId,
score: r.score,
chunkType: r.chunk.chunkType
});
totalChars += r.chunk.content.length;
}
return {
query,
chunks,
estimatedTokens: Math.ceil(totalChars / 4)
};
}
var init_auto_embed = __esm({
"src/embeddings/auto-embed.ts"() {
"use strict";
init_store();
init_model();
}
});
// src/embeddings/index.ts
var embeddings_exports = {};
__export(embeddings_exports, {
DEFAULT_MODEL_CONFIG: () => DEFAULT_MODEL_CONFIG,
EmbeddingManager: () => EmbeddingManager,
VectorStore: () => VectorStore,
buildRAGContext: () => buildRAGContext,
chunkCodeEntities: () => chunkCodeEntities,
chunkDecision: () => chunkDecision,
chunkDocComments: () => chunkDocComments,
chunkFile: () => chunkFile,
chunkIssue: () => chunkIssue,
chunkMarkdown: () => chunkMarkdown,
chunkMilestone: () => chunkMilestone,
chunkSummary: () => chunkSummary,
cosineSimilarity: () => cosineSimilarity,
createAutoEmbedMiddleware: () => createAutoEmbedMiddleware,
embed: () => embed,
embedBatch: () => embedBatch,
loadModel: () => loadModel,
resetModel: () => resetModel,
slidingWindow: () => slidingWindow
});
var init_embeddings = __esm({
"src/embeddings/index.ts"() {
init_types();
init_model();
init_store();
init_search();
init_auto_embed();
init_chunker();
}
});
export {
DEFAULT_MODEL_CONFIG,
loadModel,
embed,
embedBatch,
resetModel,
init_model,
VectorStore,
cosineSimilarity,
init_store,
chunkIssue,
chunkDecision,
chunkMilestone,
chunkMarkdown,
chunkCodeEntities,
chunkDocComments,
chunkSummary,
chunkFile,
slidingWindow,
EmbeddingManager,
createAutoEmbedMiddleware,
buildRAGContext,
init_auto_embed,
embeddings_exports,
init_embeddings
};