UNPKG

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
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 };