diff --git a/TODO.md b/TODO.md index 98e472b..794ba60 100644 --- a/TODO.md +++ b/TODO.md @@ -139,8 +139,8 @@ These items **must** be completed to have a usable system. Without them, users c - Link pages via `prevPageId`/`nextPageId` - Initialise `PageActivity` records with zero counts -- [ ] **P0-C2:** Implement `hippocampus/Ingest.ts` (minimal version) - - Entry point: `ingestText(text, modelProfile, vectorStore, metadataStore, keyPair)` +- [x] **P0-C2:** Implement `hippocampus/Ingest.ts` (minimal version) + - Entry point: `ingestText(text, { modelProfile, embeddingRunner, vectorStore, metadataStore, keyPair, ... })` - Chunk text via `Chunker` - Batch embed chunks via `EmbeddingRunner` - Persist vectors to `VectorStore` diff --git a/hippocampus/Ingest.ts b/hippocampus/Ingest.ts index 0f3fba2..e8257bf 100644 --- a/hippocampus/Ingest.ts +++ b/hippocampus/Ingest.ts @@ -1,4 +1,5 @@ -import type { Book, ModelProfile, MetadataStore, VectorStore } from "../core/types"; +import type { Book, MetadataStore, VectorStore } from "../core/types"; +import type { ModelProfile } from "../core/ModelProfile"; import { hashText } from "../core/crypto/hash"; import type { KeyPair } from "../core/crypto/sign"; import { EmbeddingRunner } from "../embeddings/EmbeddingRunner"; diff --git a/hippocampus/PageBuilder.ts b/hippocampus/PageBuilder.ts index cd79464..d03e9e3 100644 --- a/hippocampus/PageBuilder.ts +++ b/hippocampus/PageBuilder.ts @@ -1,5 +1,4 @@ import type { Hash, Page } from "../core/types"; -import type { KeyPair } from "../core/crypto/sign"; import { hashBinary, hashText } from "../core/crypto/hash"; import { signData } from "../core/crypto/sign"; @@ -43,10 +42,10 @@ export async function buildPage(options: BuildPageOptions): Promise { const contentHash = await hashText(content); const pageId = contentHash; - const rawVector = embedding.buffer.slice( - embedding.byteOffset, - embedding.byteOffset + embedding.byteLength, - ); + // Copy into a new ArrayBuffer-backed view so we never pass a SharedArrayBuffer + // into WebCrypto (and keep TypeScript happy). + const rawVector = new Uint8Array(embedding.byteLength); + rawVector.set(new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength)); const vectorHash = await hashBinary(rawVector); const unsignedPage = { diff --git a/tests/hippocampus/PageBuilder.test.ts b/tests/hippocampus/PageBuilder.test.ts index 3498f6a..5559b9a 100644 --- a/tests/hippocampus/PageBuilder.test.ts +++ b/tests/hippocampus/PageBuilder.test.ts @@ -6,7 +6,7 @@ import { generateKeyPair } from "../../core/crypto/sign"; import { verifySignature } from "../../core/crypto/verify"; import { hashBinary, hashText } from "../../core/crypto/hash"; -function canonicalizePageForSigning(page: Omit) { +function canonicalizePageForSigning(page: Page) { return JSON.stringify({ pageId: page.pageId, content: page.content, @@ -44,9 +44,10 @@ describe("buildPage", () => { expect(page.pageId).toBe(expectedContentHash); expect(page.contentHash).toBe(expectedContentHash); - const rawVector = embedding.buffer.slice( + const rawVector = new Uint8Array( + embedding.buffer, embedding.byteOffset, - embedding.byteOffset + embedding.byteLength, + embedding.byteLength, ); const expectedVectorHash = await hashBinary(rawVector); expect(page.vectorHash).toBe(expectedVectorHash);