Wave 0: shared contracts + extension points
- src/core/contracts.ts: plan tree / graph / ledger / job protocol / artifact
registry types — the single source of truth for all workstreams
- tools: per-request factory createTeacherTools({chatId}) composing
questionTools + planTools (stub) + jobTools (stub); quiz gains nodeId
- prompt composition: system-prompt.md + sorted src/agent/prompts/*.md
- ChatRecord.tree + saveTree; pending gate scoped to quiz/ask (+findPendingJobCall)
- chat.tsx: artifact renderer extension point + ChatActionsContext.syncFromServer
This commit is contained in:
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { UIMessage } from "ai";
|
||||
import { PATHS } from "../../config.ts";
|
||||
import type { PlanTree } from "../core/contracts.ts";
|
||||
|
||||
/**
|
||||
* Chat store — one JSON file per chat in data/chats/.
|
||||
@@ -19,6 +20,8 @@ export interface ChatRecord {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
messages: UIMessage[];
|
||||
/** The session's plan tree (vision §2) — written by plan tools via saveTree. */
|
||||
tree?: PlanTree;
|
||||
}
|
||||
|
||||
export interface ChatSummary {
|
||||
@@ -80,6 +83,16 @@ export function saveMessages(id: string, messages: UIMessage[]): void {
|
||||
fs.writeFileSync(chatFile(id), JSON.stringify(record, null, "\t"), "utf-8");
|
||||
}
|
||||
|
||||
/** Persist the session plan tree (plan tools call this in execute). */
|
||||
export function saveTree(id: string, tree: PlanTree): void {
|
||||
const record = getChat(id);
|
||||
if (!record) throw new Error(`Chat not found: ${id}`);
|
||||
record.tree = tree;
|
||||
// Deliberately does NOT bump updatedAt: tree mutations piggyback on the
|
||||
// turn's saveMessages, and sidebar ordering shouldn't churn on tree edits.
|
||||
fs.writeFileSync(chatFile(id), JSON.stringify(record, null, "\t"), "utf-8");
|
||||
}
|
||||
|
||||
/** Derive a short title from the first user message. */
|
||||
export function titleFromPrompt(prompt: string): string {
|
||||
const oneLine = prompt.replace(/\s+/g, " ").trim();
|
||||
|
||||
Reference in New Issue
Block a user