session kind: ChatRecord.kind teach|practice (absent = teach)
Practice sessions (owner, 2026-10-04): the marker rides the record and
the normalized summary (absent field reads as teach — pre-practice
records never migrate); POST /api/chats accepts {kind: 'practice'}.
The agent branch, tools, and UI land in the following slices.
This commit is contained in:
+6
-1
@@ -31,7 +31,7 @@ function chatFile(id: string): string {
|
||||
* phase, busy, pendingQuestion) is already announced by turn-started /
|
||||
* turn-settled, which the sidebar refetches on. Silence here is law,
|
||||
* not oversight. */
|
||||
function createChat(title: string): ChatRecord {
|
||||
function createChat(title: string, kind?: "practice"): ChatRecord {
|
||||
const now = new Date().toISOString();
|
||||
const record: ChatRecord = {
|
||||
id: `chat_${Date.now().toString(36)}_${crypto.randomUUID().slice(0, 8)}`,
|
||||
@@ -39,6 +39,9 @@ function createChat(title: string): ChatRecord {
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
messages: [],
|
||||
// Practice sessions carry the marker; teach stays ABSENT (absence
|
||||
// reads as teach — pre-practice records never migrate).
|
||||
...(kind === "practice" ? { kind: "practice" as const } : {}),
|
||||
};
|
||||
fs.mkdirSync(PATHS.chats, { recursive: true });
|
||||
fs.writeFileSync(chatFile(record.id), JSON.stringify(record, null, "\t"), "utf-8");
|
||||
@@ -73,6 +76,8 @@ function listChats(): ChatSummary[] {
|
||||
// summaries; usage aggregates ride the full record, the picker
|
||||
// never needs them).
|
||||
...summary,
|
||||
// Normalized kind: absent record field reads as teach.
|
||||
kind: summary.kind ?? "teach",
|
||||
messageCount: messages.length,
|
||||
// Record-derived status for the session picker: phase from the
|
||||
// transcript's explicit events (probe_done concluded / verdict
|
||||
|
||||
Reference in New Issue
Block a user