Something went wrong. Try again.
Original-language reader for Kant, Aristotle & more: select any passage to gloss, translate, or hear it read aloud, with exact citations.
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849import { anchorIndexAt } from "@/lib/model/locus"import type { DocumentModel, HeadingNode } from "@/lib/schemas/model"
/** * The AI request envelope (MVP §9, DATA-ARCHITECTURE "Request envelope"): the * context an AI call carries alongside the normalized quote — its full containing * paragraph and the heading breadcrumbs for its position — plus the nearest * preceding locus anchor (the cache row's `locusAnchor`, for the §12 locus index). * Pure functions of the Tier-1 model; no DOM. */
export interface Envelope { /** The full text of the block containing the offset (paragraph or heading). */ paragraph: string /** Heading labels from the outermost down to the active one (Work › … › §). */ breadcrumbs: string[] /** Nearest preceding anchor id, "" if the text has none. */ locusAnchor: string}
function pathToHeading( nodes: readonly HeadingNode[], offset: number, trail: HeadingNode[],): HeadingNode[] { // The active child at this level is the last heading whose label starts at or // before the offset; descend into it to extend the breadcrumb trail. let active: HeadingNode | null = null for (const n of nodes) { if (n.start <= offset) active = n else break } if (!active) return trail trail.push(active) return pathToHeading(active.children, offset, trail)}
export function buildEnvelope(model: DocumentModel, offset: number): Envelope { const block = model.blocks.find((b) => b.start <= offset && offset < b.end) const paragraph = block ? model.text.slice(block.start, block.end) : ""
const breadcrumbs = pathToHeading(model.headings, offset, []).map((h) => h.label)
const idx = anchorIndexAt(model, offset) const locusAnchor = idx >= 0 ? (model.anchors[idx]?.id ?? "") : ""
return { paragraph, breadcrumbs, locusAnchor }}