The knowledge graph's write channel is now the pivot's target
architecture (vision §1 construction):
- src/agent/subagents/extraction.ts — the pipeline factory
(createExtractionPipeline({ chatStore, graphStore, extractor?,
auditor? }); models env LH_EXTRACT_MODEL ?? LH_MODEL):
* transcriptView(): the compact view both LLM stages see — final plan
tree with node ids, conversation verbatim, QUIZ lines with outcomes,
mark_done lines; job tool parts are one-liners, plan ops fold into
the tree line.
* Extractor: transcript → SessionFindings (propositions incl.
misconceptions and prose-only supports edges, attribution for
UNTAGGED probes, all with verbatim evidence) via one zod-validated
submit_findings call.
* Auditor: transcript + findings → the verified subset + drops (the
faithfulness net) via submit_review.
- src/core/graph.ts — emitChat/foldStaleChats/replayFinalTree retire;
mergeFindings() replaces them as the pipeline's deterministic apply
stage: exact/alias identity resolution (one mapping line per (chat,
graph node)), edge dedupe, and event rebuild FROM THE TRANSCRIPT's tool
parts — kinds/timestamps/refs/notes deterministic, the LLM's only event
say being WHICH proposition an untagged probe tested (retroactive —
the vision's open question #3, resolved structurally: tagged events
resolve deterministically; attribution rescues untagged and
tagged-but-unmapped ones; unattributable land null + question text).
pendingQuizAnswers() is the trigger helper.
- Trigger (turn-service.ts triggerExtraction, replacing the old
foldTurnIntoGraph body): once a chat accumulates
EXTRACTION.everyNQuizAnswers (LH_EXTRACT_N, default 3) new answered
quizzes, fire the pipeline async — single-flight per chat, failure
checkpoints nothing and re-runs on the next trigger. Deliberately a v1
placeholder isolated in ONE seam, trigger-agnostic pipeline.
- GET /api/graph is now a pure read (foldStaleChats gone).
- NodeMapping.treeNodeId → sourceId (the mapping key is now the writer's
local proposition id — tree node when tree-derived); store strict-read
schema updated. Local ledger data regenerates through the pipeline.
- Tests: graph.test.ts rewritten around mergeFindings (identity,
attribution paths incl. ghost-rescue, idempotency, cross-session
provenance, trigger counting), graph-context.test.ts merge section
converted to findings-driven, NEW extraction.test.ts — transcriptView
units + the full pipeline with mock models (audit drops, failure
checkpoints nothing, single-flight). 195/195, tsc/eslint/build clean.
Probe attribution (vision open question): probes attach retroactively by
the extractor against the whole transcript; a pre-tree probe maps to a
proposition the tree only articulates later. Fuzzy/embedding merge
adjudication stays deferred (conservative exact/alias only).
38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
/** Repository root (this file is at <root>/config.ts). */
|
|
export const ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
export const PATHS = {
|
|
root: ROOT,
|
|
/** Teacher system prompt — the agent's instructions (src/agent/). */
|
|
teacherPrompt: path.join(ROOT, "src", "agent", "system-prompt.md"),
|
|
data: path.join(ROOT, "data"),
|
|
/** Chat sessions (AI SDK UIMessage transcripts, one JSON file per chat). */
|
|
chats: path.join(ROOT, "data", "chats"),
|
|
graph: path.join(ROOT, "data", "graph"),
|
|
} as const;
|
|
|
|
/**
|
|
* The extraction pipeline (vision §1 construction): the sole graph writer.
|
|
* Triggered per chat once this many NEW quiz answers have landed since the
|
|
* chat's last extraction checkpoint (LH_EXTRACT_N). The trigger mechanism is
|
|
* a v1 placeholder — deliberately isolated behind one seam
|
|
* (server/turn-service.ts) so it can be swapped without touching the
|
|
* pipeline.
|
|
*/
|
|
export const EXTRACTION = { everyNQuizAnswers: Number(process.env.LH_EXTRACT_N ?? 3) } as const;
|
|
|
|
/**
|
|
* The LIVE graph store (src/store/graph.ts) — owned by the app's extraction
|
|
* pipeline. Line shapes: src/core/contracts.ts.
|
|
*/
|
|
export const LEDGER_FILES = {
|
|
nodes: path.join(PATHS.graph, "nodes.jsonl"),
|
|
edges: path.join(PATHS.graph, "edges.jsonl"),
|
|
events: path.join(PATHS.graph, "events.jsonl"),
|
|
mappings: path.join(PATHS.graph, "mappings.jsonl"),
|
|
sessions: path.join(PATHS.graph, "sessions.jsonl"),
|
|
} as const;
|