dsh-diagnostic-tutor 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -59
- package/lib/api.js +178 -0
- package/lib/api.js.map +1 -1
- package/lib/block-types.js +25 -0
- package/lib/block-types.js.map +1 -0
- package/lib/client.js +9448 -1654
- package/lib/client.js.map +1 -1
- package/lib/diagnostics.js +170 -0
- package/lib/diagnostics.js.map +1 -0
- package/lib/index.js +75 -13
- package/lib/index.js.map +1 -1
- package/lib/insights.js +82 -0
- package/lib/insights.js.map +1 -0
- package/lib/interactions.js +70 -0
- package/lib/interactions.js.map +1 -0
- package/lib/journal.js +122 -0
- package/lib/journal.js.map +1 -0
- package/lib/lesson-markdown.js +72 -0
- package/lib/lesson-markdown.js.map +1 -0
- package/lib/lesson.js +152 -3
- package/lib/lesson.js.map +1 -1
- package/lib/math.js +126 -0
- package/lib/math.js.map +1 -0
- package/lib/path-api.js +140 -0
- package/lib/path-api.js.map +1 -0
- package/lib/path-runtime.js +361 -0
- package/lib/path-runtime.js.map +1 -0
- package/lib/path-tools.js +107 -0
- package/lib/path-tools.js.map +1 -0
- package/lib/path.js +179 -0
- package/lib/path.js.map +1 -0
- package/lib/plan-tools.js +89 -0
- package/lib/plan-tools.js.map +1 -0
- package/lib/plan.js +82 -0
- package/lib/plan.js.map +1 -0
- package/lib/project-session.js +48 -0
- package/lib/project-session.js.map +1 -0
- package/lib/prompt.js +4 -19
- package/lib/prompt.js.map +1 -1
- package/lib/review-sync.js +51 -0
- package/lib/review-sync.js.map +1 -0
- package/lib/review-tools.js +115 -0
- package/lib/review-tools.js.map +1 -0
- package/lib/review.js +103 -0
- package/lib/review.js.map +1 -0
- package/lib/source-schema.js +24 -0
- package/lib/source-schema.js.map +1 -0
- package/lib/source-tools.js +61 -0
- package/lib/source-tools.js.map +1 -0
- package/lib/sources.js +78 -0
- package/lib/sources.js.map +1 -0
- package/lib/state.js +148 -7
- package/lib/state.js.map +1 -1
- package/lib/tools.js +456 -40
- package/lib/tools.js.map +1 -1
- package/lib/types/api.d.ts +7 -0
- package/lib/types/api.d.ts.map +1 -1
- package/lib/types/block-types.d.ts +12 -0
- package/lib/types/block-types.d.ts.map +1 -0
- package/lib/types/contract.d.ts +33 -1
- package/lib/types/contract.d.ts.map +1 -1
- package/lib/types/diagnostics.d.ts +95 -0
- package/lib/types/diagnostics.d.ts.map +1 -0
- package/lib/types/handoff.d.ts +2 -2
- package/lib/types/index.d.ts +15 -9
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/insights.d.ts +57 -0
- package/lib/types/insights.d.ts.map +1 -0
- package/lib/types/interactions.d.ts +23 -0
- package/lib/types/interactions.d.ts.map +1 -0
- package/lib/types/journal.d.ts +57 -0
- package/lib/types/journal.d.ts.map +1 -0
- package/lib/types/lesson-markdown.d.ts +11 -0
- package/lib/types/lesson-markdown.d.ts.map +1 -0
- package/lib/types/lesson.d.ts +697 -5
- package/lib/types/lesson.d.ts.map +1 -1
- package/lib/types/math.d.ts +50 -0
- package/lib/types/math.d.ts.map +1 -0
- package/lib/types/path-api.d.ts +5 -0
- package/lib/types/path-api.d.ts.map +1 -0
- package/lib/types/path-runtime.d.ts +1558 -0
- package/lib/types/path-runtime.d.ts.map +1 -0
- package/lib/types/path-tools.d.ts +4 -0
- package/lib/types/path-tools.d.ts.map +1 -0
- package/lib/types/path.d.ts +744 -0
- package/lib/types/path.d.ts.map +1 -0
- package/lib/types/plan-tools.d.ts +4 -0
- package/lib/types/plan-tools.d.ts.map +1 -0
- package/lib/types/plan.d.ts +53 -0
- package/lib/types/plan.d.ts.map +1 -0
- package/lib/types/project-session.d.ts +33 -0
- package/lib/types/project-session.d.ts.map +1 -0
- package/lib/types/prompt.d.ts.map +1 -1
- package/lib/types/review-sync.d.ts +17 -0
- package/lib/types/review-sync.d.ts.map +1 -0
- package/lib/types/review-tools.d.ts +4 -0
- package/lib/types/review-tools.d.ts.map +1 -0
- package/lib/types/review.d.ts +65 -0
- package/lib/types/review.d.ts.map +1 -0
- package/lib/types/source-schema.d.ts +31 -0
- package/lib/types/source-schema.d.ts.map +1 -0
- package/lib/types/source-tools.d.ts +4 -0
- package/lib/types/source-tools.d.ts.map +1 -0
- package/lib/types/sources.d.ts +33 -0
- package/lib/types/sources.d.ts.map +1 -0
- package/lib/types/state.d.ts +516 -9
- package/lib/types/state.d.ts.map +1 -1
- package/lib/types/tools.d.ts +3 -1
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/version.d.ts +11 -0
- package/lib/types/version.d.ts.map +1 -0
- package/lib/types/vocabulary.d.ts +2 -2
- package/lib/version.js +26 -0
- package/lib/version.js.map +1 -0
- package/package.json +20 -18
package/lib/path.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/** Course planning is separate from the evidence-backed diagnosis graph. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { LessonSchema } from './lesson.js';
|
|
4
|
+
const text = z.string().trim().min(1).max(2000);
|
|
5
|
+
const short = z.string().trim().min(1).max(200);
|
|
6
|
+
const texts = z.array(text).max(20);
|
|
7
|
+
export const EvidenceRefSchema = z.object({ nodeId: short, evidenceIndex: z.number().int().min(0) }).strict();
|
|
8
|
+
export const GoalBriefSchema = z.object({
|
|
9
|
+
purpose: z.string().max(2000),
|
|
10
|
+
outcomes: texts,
|
|
11
|
+
background: z.string().max(4000),
|
|
12
|
+
timeZone: short.refine((value) => { try {
|
|
13
|
+
new Intl.DateTimeFormat('en', { timeZone: value });
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
} }, 'Use an IANA time zone'),
|
|
19
|
+
targetDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().refine((v) => {
|
|
20
|
+
if (v === null)
|
|
21
|
+
return true;
|
|
22
|
+
const stamp = Date.parse(`${v}T12:00:00Z`);
|
|
23
|
+
return Number.isFinite(stamp) && new Date(stamp).toISOString().slice(0, 10) === v;
|
|
24
|
+
}, 'Use a valid date'),
|
|
25
|
+
durationWeeks: z.number().int().min(1).max(260).nullable(),
|
|
26
|
+
deadline: z.enum(['none', 'flexible', 'fixed']),
|
|
27
|
+
weeklyMinutes: z.number().int().min(15).max(10080).nullable(),
|
|
28
|
+
sessionMinutes: z.number().int().min(5).max(480).nullable(),
|
|
29
|
+
preferences: z.string().max(2000),
|
|
30
|
+
}).strict().superRefine((brief, ctx) => {
|
|
31
|
+
if (brief.targetDate !== null && brief.durationWeeks !== null)
|
|
32
|
+
ctx.addIssue({ code: 'custom', message: 'Choose a target date or duration, not both' });
|
|
33
|
+
if (brief.deadline !== 'none' && brief.targetDate === null && brief.durationWeeks === null)
|
|
34
|
+
ctx.addIssue({ code: 'custom', message: 'Specify a target date or duration' });
|
|
35
|
+
if (brief.deadline === 'none' && (brief.targetDate !== null || brief.durationWeeks !== null))
|
|
36
|
+
ctx.addIssue({ code: 'custom', message: 'No deadline must not include a hidden date or duration' });
|
|
37
|
+
});
|
|
38
|
+
export const AssessmentSchema = z.object({
|
|
39
|
+
status: z.enum(['in-progress', 'ready', 'skipped']),
|
|
40
|
+
summary: text,
|
|
41
|
+
strengths: texts,
|
|
42
|
+
gaps: texts,
|
|
43
|
+
uncertainties: texts,
|
|
44
|
+
evidence: z.array(EvidenceRefSchema).max(40),
|
|
45
|
+
briefRevision: z.number().int().min(1),
|
|
46
|
+
sessionId: short,
|
|
47
|
+
updatedAt: z.string(),
|
|
48
|
+
}).strict();
|
|
49
|
+
export const CurriculumModuleSchema = z.object({ id: short, title: short, overview: text, outcomes: texts, milestone: text }).strict();
|
|
50
|
+
export const CurriculumItemSchema = z.object({
|
|
51
|
+
id: short,
|
|
52
|
+
moduleId: short,
|
|
53
|
+
title: short,
|
|
54
|
+
overview: text,
|
|
55
|
+
outcomes: texts.min(1),
|
|
56
|
+
outline: texts.min(1),
|
|
57
|
+
topics: texts.min(1),
|
|
58
|
+
nodeIds: z.array(short).max(20),
|
|
59
|
+
practice: text,
|
|
60
|
+
assessment: text,
|
|
61
|
+
minutes: z.object({ min: z.number().int().min(5).max(1440), max: z.number().int().min(5).max(2880) }).strict().refine((v) => v.max >= v.min, 'Maximum time must be at least minimum time'),
|
|
62
|
+
}).strict();
|
|
63
|
+
export const CurriculumEdgeSchema = z.object({ from: short, to: short, kind: z.enum(['required', 'optional']) }).strict();
|
|
64
|
+
export const CurriculumInputSchema = z.object({
|
|
65
|
+
title: short,
|
|
66
|
+
summary: text,
|
|
67
|
+
modules: z.array(CurriculumModuleSchema).min(1).max(16),
|
|
68
|
+
// This array is the complete recommended lesson order, independent of node creation order.
|
|
69
|
+
items: z.array(CurriculumItemSchema).min(1).max(80),
|
|
70
|
+
edges: z.array(CurriculumEdgeSchema).max(240),
|
|
71
|
+
assumptions: texts,
|
|
72
|
+
changeReason: text,
|
|
73
|
+
}).strict().superRefine((plan, ctx) => {
|
|
74
|
+
const moduleIds = new Set(plan.modules.map((m) => m.id));
|
|
75
|
+
const ids = new Set(plan.items.map((item) => item.id));
|
|
76
|
+
if (moduleIds.size !== plan.modules.length || ids.size !== plan.items.length)
|
|
77
|
+
ctx.addIssue({ code: 'custom', message: 'Module and lesson IDs must be unique' });
|
|
78
|
+
const index = new Map(plan.items.map((item, i) => [item.id, i]));
|
|
79
|
+
for (const item of plan.items)
|
|
80
|
+
if (!moduleIds.has(item.moduleId))
|
|
81
|
+
ctx.addIssue({ code: 'custom', message: `Unknown module for ${item.id}` });
|
|
82
|
+
for (const module of plan.modules)
|
|
83
|
+
if (!plan.items.some((item) => item.moduleId === module.id))
|
|
84
|
+
ctx.addIssue({ code: 'custom', message: `Empty module ${module.id}` });
|
|
85
|
+
const edges = new Set();
|
|
86
|
+
for (const edge of plan.edges) {
|
|
87
|
+
const key = JSON.stringify([edge.from, edge.to]);
|
|
88
|
+
if (!ids.has(edge.from) || !ids.has(edge.to) || edge.from === edge.to || edges.has(key))
|
|
89
|
+
ctx.addIssue({ code: 'custom', message: 'Edges must be unique and reference two different lessons in this plan' });
|
|
90
|
+
edges.add(key);
|
|
91
|
+
// Requiring every hard prerequisite to precede its target also proves acyclicity.
|
|
92
|
+
if (edge.kind === 'required' && (index.get(edge.from) ?? Infinity) >= (index.get(edge.to) ?? -1))
|
|
93
|
+
ctx.addIssue({ code: 'custom', message: 'Required prerequisites must precede their targets in recommended order; cycles are refused' });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
export const CurriculumSchema = z.object({
|
|
97
|
+
...CurriculumInputSchema.shape,
|
|
98
|
+
version: z.number().int().min(1),
|
|
99
|
+
briefRevision: z.number().int().min(1),
|
|
100
|
+
assessmentRevision: z.number().int().min(1),
|
|
101
|
+
createdAt: z.string(),
|
|
102
|
+
acceptedAt: z.string().nullable(),
|
|
103
|
+
}).superRefine((route, ctx) => {
|
|
104
|
+
const { version: _version, briefRevision: _brief, assessmentRevision: _assessment, createdAt: _created, acceptedAt: _accepted, ...proposal } = route;
|
|
105
|
+
const parsed = CurriculumInputSchema.safeParse(proposal);
|
|
106
|
+
if (!parsed.success)
|
|
107
|
+
for (const issue of parsed.error.issues)
|
|
108
|
+
ctx.addIssue({ code: 'custom', path: issue.path, message: issue.message });
|
|
109
|
+
});
|
|
110
|
+
export const PathRequestSchema = z.object({
|
|
111
|
+
id: short, sessionId: short, kind: z.enum(['diagnosis', 'plan']), briefRevision: z.number().int(),
|
|
112
|
+
createdAt: z.string(), prompted: z.boolean(), reason: z.string().nullable(),
|
|
113
|
+
/** Set when the prompted turn failed after the request was accepted, so the UI can retry after a restart. */
|
|
114
|
+
failure: z.string().max(2000).nullable().optional(),
|
|
115
|
+
});
|
|
116
|
+
export const LearningPathSchema = z.object({
|
|
117
|
+
courseId: short,
|
|
118
|
+
revision: z.number().int().min(0),
|
|
119
|
+
briefRevision: z.number().int().min(0),
|
|
120
|
+
assessmentRevision: z.number().int().min(0),
|
|
121
|
+
brief: GoalBriefSchema.nullable(),
|
|
122
|
+
assessment: AssessmentSchema.nullable(),
|
|
123
|
+
curricula: z.array(CurriculumSchema).max(40),
|
|
124
|
+
acceptedVersion: z.number().int().min(1).nullable(),
|
|
125
|
+
requests: z.array(PathRequestSchema).max(100),
|
|
126
|
+
updatedAt: z.string(),
|
|
127
|
+
});
|
|
128
|
+
export const BlockAnswerSchema = z.object({
|
|
129
|
+
questionId: z.string().min(1).max(200),
|
|
130
|
+
value: z.string().min(1).max(2000),
|
|
131
|
+
}).strict();
|
|
132
|
+
/** A learner's submission for one interactive block. Recording only; no judgement. */
|
|
133
|
+
export const BlockResponseSchema = z.object({
|
|
134
|
+
id: short,
|
|
135
|
+
blockId: short,
|
|
136
|
+
kind: z.enum(['quiz', 'flashcard']),
|
|
137
|
+
answers: z.array(BlockAnswerSchema).min(1).max(16),
|
|
138
|
+
submittedAt: z.string(),
|
|
139
|
+
}).strict();
|
|
140
|
+
export const CourseAttemptSchema = z.object({
|
|
141
|
+
id: short, operationId: short, operations: z.array(short).max(100), dispatchId: short.nullable(), version: z.number().int().min(1), itemId: short,
|
|
142
|
+
status: z.enum(['requested', 'working', 'completed', 'interrupted']),
|
|
143
|
+
nodeId: short.nullable(),
|
|
144
|
+
startedAt: z.string(), updatedAt: z.string(),
|
|
145
|
+
prompted: z.boolean(), promptReason: z.string().nullable(),
|
|
146
|
+
outcome: z.string().max(2000).nullable(), evidence: z.array(EvidenceRefSchema).max(40),
|
|
147
|
+
// Snapshot each teaching write. A later replace or another conversation cannot rewrite history.
|
|
148
|
+
units: z.array(z.object({ id: short, writtenAt: z.string(), lesson: LessonSchema })).max(160),
|
|
149
|
+
/** Interactive block submissions. Optional so old v1 attempts keep opening. */
|
|
150
|
+
responses: z.array(BlockResponseSchema).max(50).optional(),
|
|
151
|
+
});
|
|
152
|
+
export const CourseRunSchema = z.object({
|
|
153
|
+
courseId: short, sessionId: short, revision: z.number().int().min(0),
|
|
154
|
+
activeAttemptId: short.nullable(), attempts: z.array(CourseAttemptSchema).max(200),
|
|
155
|
+
updatedAt: z.string(),
|
|
156
|
+
});
|
|
157
|
+
export function emptyPath(courseId, now) {
|
|
158
|
+
return { courseId, revision: 0, briefRevision: 0, assessmentRevision: 0, brief: null, assessment: null, curricula: [], acceptedVersion: null, requests: [], updatedAt: now };
|
|
159
|
+
}
|
|
160
|
+
export function emptyRun(courseId, sessionId, now) {
|
|
161
|
+
return { courseId, sessionId, revision: 0, activeAttemptId: null, attempts: [], updatedAt: now };
|
|
162
|
+
}
|
|
163
|
+
export function activeAttempt(run) {
|
|
164
|
+
return run?.attempts.find((attempt) => attempt.id === run.activeAttemptId);
|
|
165
|
+
}
|
|
166
|
+
export function briefReady(brief) {
|
|
167
|
+
return !!brief?.purpose.trim() && brief.outcomes.length > 0;
|
|
168
|
+
}
|
|
169
|
+
export function pathBudget(brief, plan, now) {
|
|
170
|
+
const total = plan?.items.reduce((sum, item) => ({ min: sum.min + item.minutes.min, max: sum.max + item.minutes.max }), { min: 0, max: 0 }) ?? { min: 0, max: 0 };
|
|
171
|
+
let weeks = brief?.durationWeeks ?? null;
|
|
172
|
+
if (brief?.targetDate) {
|
|
173
|
+
const today = new Intl.DateTimeFormat('en-CA', { timeZone: brief.timeZone, year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date(now));
|
|
174
|
+
weeks = Math.max(0, (Date.parse(`${brief.targetDate}T12:00:00Z`) - Date.parse(`${today}T12:00:00Z`)) / 604800000);
|
|
175
|
+
}
|
|
176
|
+
const available = weeks === null || !brief?.weeklyMinutes ? null : Math.floor(weeks * brief.weeklyMinutes);
|
|
177
|
+
return { ...total, available, conflict: available !== null && total.min > available, tight: available !== null && total.max > available };
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=path.js.map
|
package/lib/path.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;AAG7G,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC;QAAC,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,IAAI,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC,CAAC,CAAC,EAAE,uBAAuB,CAAC;IAC9J,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1E,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IACnF,CAAC,EAAE,kBAAkB,CAAC;IACtB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC1D,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAC/C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IAC7D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;CAClC,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACrC,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI;QAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4CAA4C,EAAE,CAAC,CAAA;IACtJ,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI;QAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAA;IAC1K,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;QAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wDAAwD,EAAE,CAAC,CAAA;AACnM,CAAC,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACnD,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,KAAK;IACX,aAAa,EAAE,KAAK;IACpB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAC,MAAM,EAAE,CAAA;AAGX,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;AACtI,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,KAAK;IACT,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,IAAI;IACd,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/B,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,4CAA4C,CAAC;CAC3L,CAAC,CAAC,MAAM,EAAE,CAAA;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;AACzH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACvD,2FAA2F;IAC3F,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACnD,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC7C,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,IAAI;CACnB,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACpC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IACtD,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAA;IAC/J,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAChE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;QAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,sBAAsB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IAC5I,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IACtK,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAChD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,uEAAuE,EAAE,CAAC,CAAA;QAC3M,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACd,kFAAkF;QAClF,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4FAA4F,EAAE,CAAC,CAAA;IAC3O,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,GAAG,qBAAqB,CAAC,KAAK;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC5B,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAA;IACpJ,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACxD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;YAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;AAC1I,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACjG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3E,6GAA6G;IAC7G,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACpD,CAAC,CAAA;AACF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,KAAK,EAAE,eAAe,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACvC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACnD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;CACnC,CAAC,CAAC,MAAM,EAAE,CAAA;AAGX,sFAAsF;AACtF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,EAAE,EAAE,KAAK;IACT,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC,MAAM,EAAE,CAAA;AAGX,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK;IACjJ,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IACpE,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE;IACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACtF,gGAAgG;IAChG,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC7F,+EAA+E;IAC/E,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC3D,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE,eAAe,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAClF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAA;AAGF,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,GAAW;IACrD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA;AAC9K,CAAC;AACD,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,SAAiB,EAAE,GAAW;IACvE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA;AAClG,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,GAAiC;IAC7D,OAAO,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,CAAC,eAAe,CAAC,CAAA;AAC5E,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,KAAuB;IAChD,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;AAC7D,CAAC;AACD,MAAM,UAAU,UAAU,CAAC,KAAuB,EAAE,IAAyC,EAAE,GAAW;IACxG,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAA;IACjK,IAAI,KAAK,GAAG,KAAK,EAAE,aAAa,IAAI,IAAI,CAAA;IACxC,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QACrJ,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,UAAU,YAAY,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;IACnH,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,CAAA;IAC1G,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,GAAG,SAAS,EAAE,CAAA;AAC3I,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Model-facing plan items. Planning is runtime policy, not a teaching decision. */
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
4
|
+
import { MAX_TASKS, TaskInputSchema, sortTasks, taskView } from './plan.js';
|
|
5
|
+
function output() {
|
|
6
|
+
return { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }] };
|
|
7
|
+
}
|
|
8
|
+
function validateInput(state, raw, index) {
|
|
9
|
+
const input = TaskInputSchema.parse(raw);
|
|
10
|
+
if (input.dueAt !== undefined && !Number.isFinite(Date.parse(input.dueAt)))
|
|
11
|
+
throw new Error(`task[${index}] has an invalid dueAt`);
|
|
12
|
+
if (input.courseId !== undefined) {
|
|
13
|
+
const course = state.readCourse(input.courseId);
|
|
14
|
+
if (course === undefined)
|
|
15
|
+
throw new Error(`task[${index}] references an unknown course`);
|
|
16
|
+
if (input.nodeId !== undefined && state.readNode(input.nodeId)?.courseId !== input.courseId)
|
|
17
|
+
throw new Error(`task[${index}] references a node outside the course`);
|
|
18
|
+
}
|
|
19
|
+
else if (input.nodeId !== undefined) {
|
|
20
|
+
throw new Error(`task[${index}] cannot name a node without its course`);
|
|
21
|
+
}
|
|
22
|
+
if (input.sourceId !== undefined && state.readSource(input.sourceId) === undefined)
|
|
23
|
+
throw new Error(`task[${index}] references an unknown source`);
|
|
24
|
+
return input;
|
|
25
|
+
}
|
|
26
|
+
function materialize(input, now) {
|
|
27
|
+
return {
|
|
28
|
+
id: randomUUID(), title: input.title, status: 'open', createdAt: now, updatedAt: now,
|
|
29
|
+
...(input.courseId === undefined ? {} : { courseId: input.courseId }),
|
|
30
|
+
...(input.nodeId === undefined ? {} : { nodeId: input.nodeId }),
|
|
31
|
+
...(input.dueAt === undefined ? {} : { dueAt: input.dueAt }),
|
|
32
|
+
...(input.estimateMin === undefined ? {} : { estimateMin: input.estimateMin }),
|
|
33
|
+
...(input.sourceId === undefined ? {} : { sourceId: input.sourceId }),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function planTools(state) {
|
|
37
|
+
return [
|
|
38
|
+
defineTool({
|
|
39
|
+
name: 'udt_plan_get',
|
|
40
|
+
description: 'Read the learner-owned Today plan: open first, dated tasks in due order, then undated tasks. Plan items are not teaching decisions and do not change knowledge state.',
|
|
41
|
+
parameters: {},
|
|
42
|
+
output: output(),
|
|
43
|
+
execute: async () => JSON.parse(JSON.stringify({ now: new Date().toISOString(), tasks: sortTasks(state.listTasks()).map((task) => taskView(task)) })),
|
|
44
|
+
}),
|
|
45
|
+
defineTool({
|
|
46
|
+
name: 'udt_plan_update',
|
|
47
|
+
description: 'Maintain the learner-visible Today plan. Planning is runtime policy, not a teaching judgement: it does not change a node state, complete a lesson or call a model. ' +
|
|
48
|
+
'op=add creates tasks (title, optional courseId/nodeId/dueAt/estimateMin/sourceId); op=complete marks one done; op=remove deletes one. ' +
|
|
49
|
+
'Use a real ISO date-time for dueAt; tasks without dueAt stay in Today but are not in the ICS calendar. Never invent a sourceId.',
|
|
50
|
+
parameters: {
|
|
51
|
+
op: { type: 'string', required: true, enum: ['add', 'complete', 'remove'] },
|
|
52
|
+
tasks: { type: 'array', description: 'For op=add: one or more tasks.' },
|
|
53
|
+
taskId: { type: 'string', description: 'For op=complete/remove.' },
|
|
54
|
+
},
|
|
55
|
+
output: output(),
|
|
56
|
+
execute: async (args) => {
|
|
57
|
+
const input = args;
|
|
58
|
+
const now = new Date().toISOString();
|
|
59
|
+
if (input.op === 'add') {
|
|
60
|
+
if (!Array.isArray(input.tasks) || input.tasks.length === 0)
|
|
61
|
+
throw new Error('plan-add-needs-tasks');
|
|
62
|
+
if (state.listTasks().length + input.tasks.length > MAX_TASKS)
|
|
63
|
+
throw new Error('too-many-tasks: remove or complete old tasks first');
|
|
64
|
+
const materialized = input.tasks.map((candidate, index) => materialize(validateInput(state, candidate, index), now));
|
|
65
|
+
for (const task of materialized)
|
|
66
|
+
await state.writeTask(task);
|
|
67
|
+
return JSON.parse(JSON.stringify({ ok: true, tasks: sortTasks(state.listTasks()).map((task) => taskView(task)) }));
|
|
68
|
+
}
|
|
69
|
+
if (input.op === 'complete' || input.op === 'remove') {
|
|
70
|
+
const taskId = input.taskId;
|
|
71
|
+
if (taskId === undefined)
|
|
72
|
+
throw new Error('plan-update-needs-taskId');
|
|
73
|
+
const task = state.readTask(taskId);
|
|
74
|
+
if (task === undefined)
|
|
75
|
+
throw new Error('no-such-task: read udt_plan_get');
|
|
76
|
+
if (input.op === 'complete') {
|
|
77
|
+
await state.writeTask({ ...task, status: 'done', updatedAt: now });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await state.deleteTask(taskId);
|
|
81
|
+
}
|
|
82
|
+
return JSON.parse(JSON.stringify({ ok: true, tasks: sortTasks(state.listTasks()).map((task) => taskView(task)) }));
|
|
83
|
+
}
|
|
84
|
+
throw new Error('unknown-plan-operation');
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=plan-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-tools.js","sourceRoot":"","sources":["../src/plan-tools.ts"],"names":[],"mappings":"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"}
|
package/lib/plan.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Learner-owned plan items and ICS projection. No teaching decisions. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const TASK_STATUSES = ['open', 'done', 'archived'];
|
|
4
|
+
export const TASKS_TABLE = 'tasks';
|
|
5
|
+
export const MAX_TASKS = 200;
|
|
6
|
+
export const MAX_TASK_TITLE_CHARS = 200;
|
|
7
|
+
export const MAX_TASK_ESTIMATE_MINUTES = 480;
|
|
8
|
+
export const MIN_TASK_ESTIMATE_MINUTES = 5;
|
|
9
|
+
export const TaskSchema = z.object({
|
|
10
|
+
id: z.string().min(1).max(120),
|
|
11
|
+
courseId: z.string().min(1).max(120).optional(),
|
|
12
|
+
nodeId: z.string().min(1).max(120).optional(),
|
|
13
|
+
title: z.string().min(1).max(MAX_TASK_TITLE_CHARS),
|
|
14
|
+
/** ISO date-time; omitted tasks stay visible in Today but cannot be exported to a calendar. */
|
|
15
|
+
dueAt: z.string().min(1).max(80).optional(),
|
|
16
|
+
estimateMin: z.number().int().min(MIN_TASK_ESTIMATE_MINUTES).max(MAX_TASK_ESTIMATE_MINUTES).optional(),
|
|
17
|
+
sourceId: z.string().min(1).max(120).optional(),
|
|
18
|
+
status: z.enum(TASK_STATUSES),
|
|
19
|
+
createdAt: z.string(),
|
|
20
|
+
updatedAt: z.string(),
|
|
21
|
+
}).strict();
|
|
22
|
+
export const TaskInputSchema = z.object({
|
|
23
|
+
title: z.string().trim().min(1).max(MAX_TASK_TITLE_CHARS),
|
|
24
|
+
courseId: z.string().min(1).max(120).optional(),
|
|
25
|
+
nodeId: z.string().min(1).max(120).optional(),
|
|
26
|
+
dueAt: z.string().min(1).max(80).optional(),
|
|
27
|
+
estimateMin: z.number().int().min(MIN_TASK_ESTIMATE_MINUTES).max(MAX_TASK_ESTIMATE_MINUTES).optional(),
|
|
28
|
+
sourceId: z.string().min(1).max(120).optional(),
|
|
29
|
+
}).strict();
|
|
30
|
+
export function taskView(task) {
|
|
31
|
+
return {
|
|
32
|
+
id: task.id, title: task.title, status: task.status, createdAt: task.createdAt,
|
|
33
|
+
...(task.courseId === undefined ? {} : { courseId: task.courseId }),
|
|
34
|
+
...(task.nodeId === undefined ? {} : { nodeId: task.nodeId }),
|
|
35
|
+
...(task.dueAt === undefined ? {} : { dueAt: task.dueAt }),
|
|
36
|
+
...(task.estimateMin === undefined ? {} : { estimateMin: task.estimateMin }),
|
|
37
|
+
...(task.sourceId === undefined ? {} : { sourceId: task.sourceId }),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Open tasks, earliest due first; undated tasks last. */
|
|
41
|
+
export function sortTasks(tasks) {
|
|
42
|
+
return [...tasks].sort((left, right) => {
|
|
43
|
+
if (left.status !== right.status)
|
|
44
|
+
return left.status === 'open' ? -1 : 1;
|
|
45
|
+
if (left.dueAt === undefined && right.dueAt === undefined)
|
|
46
|
+
return left.createdAt.localeCompare(right.createdAt);
|
|
47
|
+
if (left.dueAt === undefined)
|
|
48
|
+
return 1;
|
|
49
|
+
if (right.dueAt === undefined)
|
|
50
|
+
return -1;
|
|
51
|
+
return left.dueAt.localeCompare(right.dueAt);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function icsDate(value) {
|
|
55
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
56
|
+
return `${value.getUTCFullYear()}${pad(value.getUTCMonth() + 1)}${pad(value.getUTCDate())}T${pad(value.getUTCHours())}${pad(value.getUTCMinutes())}${pad(value.getUTCSeconds())}Z`;
|
|
57
|
+
}
|
|
58
|
+
function icsText(value) {
|
|
59
|
+
return value.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/,/g, '\\,').replace(/;/g, '\\;');
|
|
60
|
+
}
|
|
61
|
+
/** Render open, dated tasks as one ICS calendar. */
|
|
62
|
+
export function buildIcs(tasks, now = new Date()) {
|
|
63
|
+
const lines = [
|
|
64
|
+
'BEGIN:VCALENDAR',
|
|
65
|
+
'VERSION:2.0',
|
|
66
|
+
'PRODID:-//dsh-diagnostic-tutor//plan//EN',
|
|
67
|
+
'CALSCALE:GREGORIAN',
|
|
68
|
+
'METHOD:PUBLISH',
|
|
69
|
+
];
|
|
70
|
+
for (const task of tasks) {
|
|
71
|
+
if (task.status !== 'open' || task.dueAt === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
const start = new Date(task.dueAt);
|
|
74
|
+
if (!Number.isFinite(start.getTime()))
|
|
75
|
+
continue;
|
|
76
|
+
const end = new Date(start.getTime() + (task.estimateMin ?? 30) * 60_000);
|
|
77
|
+
lines.push('BEGIN:VEVENT', `UID:${icsText(task.id)}@dsh-diagnostic-tutor`, `DTSTAMP:${icsDate(now)}`, `DTSTART:${icsDate(start)}`, `DTEND:${icsDate(end)}`, `SUMMARY:${icsText(task.title)}`, ...(task.courseId === undefined ? [] : [`CATEGORIES:${icsText(task.courseId)}`]), 'END:VEVENT');
|
|
78
|
+
}
|
|
79
|
+
lines.push('END:VCALENDAR', '');
|
|
80
|
+
return lines.join('\r\n');
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=plan.js.map
|
package/lib/plan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which conversation should "continue learning" open?
|
|
3
|
+
*
|
|
4
|
+
* A project is shared; where the learner was last actually learning it is not.
|
|
5
|
+
* Focuses, course runs and project selections all carry a conversation id, in
|
|
6
|
+
* that order of strength: an active focus is a lesson in progress, a course run
|
|
7
|
+
* is a planned lesson that was explicitly started, and a selection only says the
|
|
8
|
+
* conversation once opened the project.
|
|
9
|
+
*
|
|
10
|
+
* The newest candidate wins. That keeps two conversations on the same project
|
|
11
|
+
* from stealing each other: whoever last acted is the one resumed, and a
|
|
12
|
+
* conversation that has not started anything never jumps ahead of one that has.
|
|
13
|
+
*
|
|
14
|
+
* Pure read-only resolution: it never selects, starts or writes anything.
|
|
15
|
+
*/
|
|
16
|
+
/** The newest record by one ISO timestamp field. */
|
|
17
|
+
function newest(records, at) {
|
|
18
|
+
return [...records].sort((left, right) => Date.parse(at(right)) - Date.parse(at(left)))[0];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the conversation that should handle "enter learning" for a project.
|
|
22
|
+
*
|
|
23
|
+
* @param state - the open state handle.
|
|
24
|
+
* @param courseId - the project being entered.
|
|
25
|
+
* @param currentSessionId - the conversation asking, used only when no stored
|
|
26
|
+
* conversation has ever touched the project.
|
|
27
|
+
* @returns the target conversation, or `null` when the project does not exist.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveLearningSession(state, courseId, currentSessionId) {
|
|
30
|
+
if (state.readCourse(courseId) === undefined)
|
|
31
|
+
return null;
|
|
32
|
+
const focus = newest(state.listFocus().filter((record) => record.courseId === courseId &&
|
|
33
|
+
record.status === 'active' &&
|
|
34
|
+
typeof record.sessionId === 'string' &&
|
|
35
|
+
record.sessionId.length > 0), (record) => record.startedAt);
|
|
36
|
+
if (focus !== undefined)
|
|
37
|
+
return { sessionId: focus.sessionId, reason: 'active-focus' };
|
|
38
|
+
const run = newest(state.listCourseRuns().filter((record) => record.courseId === courseId && record.attempts.length > 0), (record) => record.updatedAt);
|
|
39
|
+
if (run !== undefined)
|
|
40
|
+
return { sessionId: run.sessionId, reason: 'active-run' };
|
|
41
|
+
const project = newest(state.listProjects().filter((record) => record.courseId === courseId), (record) => record.selectedAt);
|
|
42
|
+
if (project !== undefined)
|
|
43
|
+
return { sessionId: project.sessionId, reason: 'recent-project' };
|
|
44
|
+
return currentSessionId !== undefined && currentSessionId.length > 0
|
|
45
|
+
? { sessionId: currentSessionId, reason: 'current' }
|
|
46
|
+
: null;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=project-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-session.js","sourceRoot":"","sources":["../src/project-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAYH,oDAAoD;AACpD,SAAS,MAAM,CAAI,OAAqB,EAAE,EAAyB;IACjE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC5F,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAc,EACd,QAAgB,EAChB,gBAAyB;IAEzB,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IAEzD,MAAM,KAAK,GAAG,MAAM,CAClB,KAAK,CAAC,SAAS,EAAE,CAAC,MAAM,CACtB,CAAC,MAAM,EAAmD,EAAE,CAC1D,MAAM,CAAC,QAAQ,KAAK,QAAQ;QAC5B,MAAM,CAAC,MAAM,KAAK,QAAQ;QAC1B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;QACpC,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAC9B,EACD,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAC7B,CAAA;IACD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAEtF,MAAM,GAAG,GAAG,MAAM,CAChB,KAAK,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EACrG,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAC7B,CAAA;IACD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,CAAA;IAEhF,MAAM,OAAO,GAAG,MAAM,CACpB,KAAK,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,EACrE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAC9B,CAAA;IACD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAA;IAE5F,OAAO,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAClE,CAAC,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE;QACpD,CAAC,CAAC,IAAI,CAAA;AACV,CAAC"}
|
package/lib/prompt.js
CHANGED
|
@@ -67,25 +67,10 @@ export function promptSession(ctx, sessionId, text) {
|
|
|
67
67
|
if (!agents) {
|
|
68
68
|
return { prompted: false, reason: 'this profile has no agent registry' };
|
|
69
69
|
}
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
let agent = agents.get(sessionId);
|
|
75
|
-
if (!agent) {
|
|
76
|
-
const live = agents.list();
|
|
77
|
-
if (live.length === 1 && live[0] !== undefined) {
|
|
78
|
-
agent = live[0];
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
return {
|
|
82
|
-
prompted: false,
|
|
83
|
-
reason: live.length === 0
|
|
84
|
-
? 'that session has no live agent yet — say anything in the chat and the tutor will pick the focus up'
|
|
85
|
-
: `that session has no live agent, and ${live.length} other conversations are open`,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
70
|
+
// Never wake a sole unrelated Agent when the requested conversation has none.
|
|
71
|
+
const agent = agents.get(sessionId);
|
|
72
|
+
if (!agent)
|
|
73
|
+
return { prompted: false, reason: 'that session has no live agent yet — say anything in the chat and retry' };
|
|
89
74
|
const target = agent;
|
|
90
75
|
target.followup(createUserMessage({
|
|
91
76
|
content: [{ type: 'text', text }],
|
package/lib/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAA;AA2B/C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB,EAAE,IAAgB;IACpE,OAAO,CACL,oBAAoB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,QAAQ,OAAO,MAAM,CAAC,KAAK,QAAQ;QAC7E,6FAA6F;QAC7F,iEAAiE,CAClE,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,SAA6B,EAAE,IAAY;IACrF,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAA;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAA;IAC1E,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAA;AA2B/C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB,EAAE,IAAgB;IACpE,OAAO,CACL,oBAAoB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,QAAQ,OAAO,MAAM,CAAC,KAAK,QAAQ;QAC7E,6FAA6F;QAC7F,iEAAiE,CAClE,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,SAA6B,EAAE,IAAY;IACrF,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAA;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAA;IAC1E,CAAC;IAED,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAkB,CAAC,CAAA;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,yEAAyE,EAAE,CAAA;IAEzH,MAAM,MAAM,GAAG,KAAK,CAAA;IACpB,MAAM,CAAC,QAAQ,CACb,iBAAiB,CAAC;QAChB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACjC,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;KAChC,CAAC,CACH,CAAA;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Project lesson flashcards into the learner-owned review queue. */
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { isKnownBlock } from './block-types.js';
|
|
4
|
+
import { MAX_REVIEW_CARDS } from './review.js';
|
|
5
|
+
function autoCardId(courseId, nodeId, blockId) {
|
|
6
|
+
return `auto-${createHash('sha256').update(`${courseId}:${nodeId}:${blockId}`).digest('hex').slice(0, 32)}`;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create or refresh one review card per flashcard block in the lesson.
|
|
10
|
+
*
|
|
11
|
+
* This is projection, not teaching: it never grades, never resets an existing
|
|
12
|
+
* schedule and never changes node state. Replacing a lesson updates the visible
|
|
13
|
+
* front/back while preserving the card's schedule. Removed flashcards are left
|
|
14
|
+
* alone rather than silently deleting review history.
|
|
15
|
+
*/
|
|
16
|
+
export async function syncLessonFlashcards(state, input) {
|
|
17
|
+
const ids = [];
|
|
18
|
+
for (const block of input.lesson.blocks) {
|
|
19
|
+
if (!isKnownBlock(block) || block.type !== 'flashcard')
|
|
20
|
+
continue;
|
|
21
|
+
const id = autoCardId(input.courseId, input.nodeId, block.id);
|
|
22
|
+
const existing = state.readReviewCard(id);
|
|
23
|
+
const sourceRefs = block.sourceRefs;
|
|
24
|
+
if (existing !== undefined) {
|
|
25
|
+
if (existing.front !== block.content.front || existing.back !== block.content.back || JSON.stringify(existing.sourceRefs) !== JSON.stringify(sourceRefs)) {
|
|
26
|
+
await state.writeReviewCard({
|
|
27
|
+
...existing,
|
|
28
|
+
front: block.content.front,
|
|
29
|
+
back: block.content.back,
|
|
30
|
+
...(sourceRefs === undefined ? {} : { sourceRefs }),
|
|
31
|
+
updatedAt: input.now,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
ids.push(id);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (state.listReviewCards().length >= MAX_REVIEW_CARDS)
|
|
38
|
+
continue;
|
|
39
|
+
const card = {
|
|
40
|
+
id, courseId: input.courseId, nodeId: input.nodeId, blockId: block.id,
|
|
41
|
+
front: block.content.front, back: block.content.back,
|
|
42
|
+
...(sourceRefs === undefined ? {} : { sourceRefs }),
|
|
43
|
+
dueAt: input.now, intervalDays: 0, ease: 2.5, reps: 0, lapses: 0,
|
|
44
|
+
status: 'open', createdAt: input.now, updatedAt: input.now,
|
|
45
|
+
};
|
|
46
|
+
await state.writeReviewCard(card);
|
|
47
|
+
ids.push(id);
|
|
48
|
+
}
|
|
49
|
+
return ids;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=review-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-sync.js","sourceRoot":"","sources":["../src/review-sync.ts"],"names":[],"mappings":"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"}
|