dsh-diagnostic-tutor 0.1.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/LICENSE +21 -0
- package/README.md +658 -0
- package/cordis.patch.yml +23 -0
- package/lib/api.js +413 -0
- package/lib/api.js.map +1 -0
- package/lib/client.js +2029 -0
- package/lib/client.js.map +1 -0
- package/lib/contract.js +14 -0
- package/lib/contract.js.map +1 -0
- package/lib/diagnosis.js +224 -0
- package/lib/diagnosis.js.map +1 -0
- package/lib/handoff.js +194 -0
- package/lib/handoff.js.map +1 -0
- package/lib/index.js +186 -0
- package/lib/index.js.map +1 -0
- package/lib/lesson.js +285 -0
- package/lib/lesson.js.map +1 -0
- package/lib/prompt.js +96 -0
- package/lib/prompt.js.map +1 -0
- package/lib/state.js +500 -0
- package/lib/state.js.map +1 -0
- package/lib/tools.js +994 -0
- package/lib/tools.js.map +1 -0
- package/lib/trust-fence.js +101 -0
- package/lib/trust-fence.js.map +1 -0
- package/lib/types/api.d.ts +62 -0
- package/lib/types/api.d.ts.map +1 -0
- package/lib/types/contract.d.ts +147 -0
- package/lib/types/contract.d.ts.map +1 -0
- package/lib/types/diagnosis.d.ts +116 -0
- package/lib/types/diagnosis.d.ts.map +1 -0
- package/lib/types/handoff.d.ts +141 -0
- package/lib/types/handoff.d.ts.map +1 -0
- package/lib/types/index.d.ts +71 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/lesson.d.ts +295 -0
- package/lib/types/lesson.d.ts.map +1 -0
- package/lib/types/prompt.d.ts +85 -0
- package/lib/types/prompt.d.ts.map +1 -0
- package/lib/types/state.d.ts +627 -0
- package/lib/types/state.d.ts.map +1 -0
- package/lib/types/tools.d.ts +38 -0
- package/lib/types/tools.d.ts.map +1 -0
- package/lib/types/trust-fence.d.ts +53 -0
- package/lib/types/trust-fence.d.ts.map +1 -0
- package/lib/types/udt.d.ts +95 -0
- package/lib/types/udt.d.ts.map +1 -0
- package/lib/types/vocabulary.d.ts +162 -0
- package/lib/types/vocabulary.d.ts.map +1 -0
- package/lib/udt.js +141 -0
- package/lib/udt.js.map +1 -0
- package/lib/vocabulary.js +182 -0
- package/lib/vocabulary.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The persistence contract for dsh-diagnostic-tutor.
|
|
3
|
+
*
|
|
4
|
+
* This module owns one Cordis **storage domain** — the official DSH
|
|
5
|
+
* persistence seam — and nothing else. It contains no teaching logic: it
|
|
6
|
+
* stores what was observed, never what should happen next.
|
|
7
|
+
*
|
|
8
|
+
* Why a storage domain rather than files of our own:
|
|
9
|
+
* - it is the supported seam; the profile routes it to a backend (the
|
|
10
|
+
* standard profiles use `dsh-storage-json` under `dshHomePath('storages')`);
|
|
11
|
+
* - **the zod schema is the contract** — every record is validated at the
|
|
12
|
+
* durable boundary, so corrupt or hand-edited data cannot enter memory;
|
|
13
|
+
* - reads are synchronous from memory and writes ride one per-domain write
|
|
14
|
+
* chain, so concurrent writers cannot interleave;
|
|
15
|
+
* - unmounting is clean: `Domain.close()` releases the backend unit.
|
|
16
|
+
*
|
|
17
|
+
* ---------------------------------------------------------------------------
|
|
18
|
+
* A refinement of the cross-version discipline (verified against source)
|
|
19
|
+
* ---------------------------------------------------------------------------
|
|
20
|
+
* The rule "import `@deepseek-ai/*` as types only" is about **stateful
|
|
21
|
+
* objects** — services, classes, instances. A second harness cohort must never
|
|
22
|
+
* supply those, because identity checks and `instanceof` would silently fail.
|
|
23
|
+
*
|
|
24
|
+
* `defineDomain` and `domainTable` are a different category: **pure builder
|
|
25
|
+
* functions**. `domainTable(schema)` is literally `{ valueSchema: schema }`,
|
|
26
|
+
* and `defineDomain(spec)` validates a spec and returns it unchanged. They
|
|
27
|
+
* take plain data and return plain data, carry no identity, and are re-exported
|
|
28
|
+
* by the host for exactly this use — the same pattern every published DSH
|
|
29
|
+
* plugin follows.
|
|
30
|
+
*
|
|
31
|
+
* The rules that still hold absolutely: never `instanceof` a returned object,
|
|
32
|
+
* and take every service instance (`DomainFacility`, `Domain`, tables) from
|
|
33
|
+
* `ctx`. Here `DomainFacility` is imported as a **type**, and the `Domain` we
|
|
34
|
+
* use is whatever the host's facility handed back.
|
|
35
|
+
*/
|
|
36
|
+
import type { DomainFacility } from '@deepseek-ai/dsh-storage-domain';
|
|
37
|
+
import { z } from 'zod';
|
|
38
|
+
import type { NodeRelation, NodeState, Readiness } from './vocabulary.js';
|
|
39
|
+
import type { LessonKey, LessonRecord } from './lesson.js';
|
|
40
|
+
import type { HandoffKey, HandoffRecord } from './handoff.js';
|
|
41
|
+
/**
|
|
42
|
+
* The learner singleton. Stored in the domain's **global** slot rather than a
|
|
43
|
+
* one-row table, because the global slot exists precisely for a single
|
|
44
|
+
* document and its `initial` value gives a well-defined "never written" state.
|
|
45
|
+
*
|
|
46
|
+
* `initializedAt` is the sentinel that distinguishes "the stored profile" from
|
|
47
|
+
* "the spec's default": it is the empty string until the first write, which is
|
|
48
|
+
* what makes first-run initialization idempotent and restart-detectable.
|
|
49
|
+
*
|
|
50
|
+
* Note there is no field for proficiency, level or score. Preferences only.
|
|
51
|
+
*/
|
|
52
|
+
export declare const LearnerProfileSchema: z.ZodObject<{
|
|
53
|
+
preferredLanguage: z.ZodOptional<z.ZodString>;
|
|
54
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
55
|
+
auto: "auto";
|
|
56
|
+
"zero-base": "zero-base";
|
|
57
|
+
standard: "standard";
|
|
58
|
+
advanced: "advanced";
|
|
59
|
+
}>>;
|
|
60
|
+
activeCourseId: z.ZodOptional<z.ZodString>;
|
|
61
|
+
initializedAt: z.ZodString;
|
|
62
|
+
updatedAt: z.ZodString;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
export type LearnerProfile = z.infer<typeof LearnerProfileSchema>;
|
|
65
|
+
/** Lifecycle of a learning goal. Not a mastery status. */
|
|
66
|
+
export declare const COURSE_STATUSES: readonly ["active", "paused", "archived"];
|
|
67
|
+
export declare const CourseStatusSchema: z.ZodEnum<{
|
|
68
|
+
active: "active";
|
|
69
|
+
paused: "paused";
|
|
70
|
+
archived: "archived";
|
|
71
|
+
}>;
|
|
72
|
+
export type CourseStatus = z.infer<typeof CourseStatusSchema>;
|
|
73
|
+
/**
|
|
74
|
+
* A learning goal in the learner's own words.
|
|
75
|
+
*
|
|
76
|
+
* `goal` is the verbatim statement that started the course; `title` is a short
|
|
77
|
+
* label for display. Neither is ever auto-expanded into a syllabus.
|
|
78
|
+
*/
|
|
79
|
+
export declare const CourseSchema: z.ZodObject<{
|
|
80
|
+
id: z.ZodString;
|
|
81
|
+
title: z.ZodString;
|
|
82
|
+
goal: z.ZodString;
|
|
83
|
+
status: z.ZodEnum<{
|
|
84
|
+
active: "active";
|
|
85
|
+
paused: "paused";
|
|
86
|
+
archived: "archived";
|
|
87
|
+
}>;
|
|
88
|
+
createdAt: z.ZodString;
|
|
89
|
+
updatedAt: z.ZodString;
|
|
90
|
+
}, z.core.$strip>;
|
|
91
|
+
export type CourseRecord = z.infer<typeof CourseSchema>;
|
|
92
|
+
/**
|
|
93
|
+
* One observation attached to a node.
|
|
94
|
+
*
|
|
95
|
+
* Evidence records *what happened*, never how good it was. There is no score,
|
|
96
|
+
* no weight and no correctness flag — a `readiness` outcome is the skill's own
|
|
97
|
+
* six-term vocabulary, and it is optional because not every observation rises
|
|
98
|
+
* to a readiness judgement.
|
|
99
|
+
*/
|
|
100
|
+
export declare const EvidenceSchema: z.ZodObject<{
|
|
101
|
+
kind: z.ZodEnum<{
|
|
102
|
+
"goal-stated": "goal-stated";
|
|
103
|
+
diagnosis: "diagnosis";
|
|
104
|
+
explanation: "explanation";
|
|
105
|
+
practice: "practice";
|
|
106
|
+
check: "check";
|
|
107
|
+
transfer: "transfer";
|
|
108
|
+
}>;
|
|
109
|
+
at: z.ZodString;
|
|
110
|
+
note: z.ZodOptional<z.ZodString>;
|
|
111
|
+
readiness: z.ZodOptional<z.ZodEnum<{
|
|
112
|
+
advance: "advance";
|
|
113
|
+
"advance-with-caution": "advance-with-caution";
|
|
114
|
+
"review-first": "review-first";
|
|
115
|
+
"step-down": "step-down";
|
|
116
|
+
"diagnose-again": "diagnose-again";
|
|
117
|
+
"more-practice": "more-practice";
|
|
118
|
+
}>>;
|
|
119
|
+
}, z.core.$strip>;
|
|
120
|
+
export type Evidence = z.infer<typeof EvidenceSchema>;
|
|
121
|
+
/**
|
|
122
|
+
* One node of the diagnosis map.
|
|
123
|
+
*
|
|
124
|
+
* Nodes are born `unconfirmed` and stay that way until evidence supports
|
|
125
|
+
* something else; see `diagnosis.ts` for the transition rules. There is no
|
|
126
|
+
* `progress`, no `weight`, no `order` and no `dueAt`: nothing here describes a
|
|
127
|
+
* schedule or a completion percentage, because the map is not a syllabus.
|
|
128
|
+
*/
|
|
129
|
+
export declare const NodeSchema: z.ZodObject<{
|
|
130
|
+
id: z.ZodString;
|
|
131
|
+
courseId: z.ZodString;
|
|
132
|
+
title: z.ZodString;
|
|
133
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
134
|
+
relation: z.ZodEnum<{
|
|
135
|
+
goal: "goal";
|
|
136
|
+
"part-of": "part-of";
|
|
137
|
+
prerequisite: "prerequisite";
|
|
138
|
+
related: "related";
|
|
139
|
+
}>;
|
|
140
|
+
state: z.ZodEnum<{
|
|
141
|
+
unconfirmed: "unconfirmed";
|
|
142
|
+
explained: "explained";
|
|
143
|
+
practiced: "practiced";
|
|
144
|
+
checked: "checked";
|
|
145
|
+
weak: "weak";
|
|
146
|
+
blocked: "blocked";
|
|
147
|
+
confirmed: "confirmed";
|
|
148
|
+
}>;
|
|
149
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
150
|
+
kind: z.ZodEnum<{
|
|
151
|
+
"goal-stated": "goal-stated";
|
|
152
|
+
diagnosis: "diagnosis";
|
|
153
|
+
explanation: "explanation";
|
|
154
|
+
practice: "practice";
|
|
155
|
+
check: "check";
|
|
156
|
+
transfer: "transfer";
|
|
157
|
+
}>;
|
|
158
|
+
at: z.ZodString;
|
|
159
|
+
note: z.ZodOptional<z.ZodString>;
|
|
160
|
+
readiness: z.ZodOptional<z.ZodEnum<{
|
|
161
|
+
advance: "advance";
|
|
162
|
+
"advance-with-caution": "advance-with-caution";
|
|
163
|
+
"review-first": "review-first";
|
|
164
|
+
"step-down": "step-down";
|
|
165
|
+
"diagnose-again": "diagnose-again";
|
|
166
|
+
"more-practice": "more-practice";
|
|
167
|
+
}>>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
169
|
+
createdAt: z.ZodString;
|
|
170
|
+
updatedAt: z.ZodString;
|
|
171
|
+
}, z.core.$strip>;
|
|
172
|
+
export type NodeRecord = z.infer<typeof NodeSchema>;
|
|
173
|
+
/**
|
|
174
|
+
* The one node being learned right now, per course.
|
|
175
|
+
*
|
|
176
|
+
* This is what makes "Start learning" an explicit act rather than an implicit
|
|
177
|
+
* one: the runtime records which node the learner asked to work on and when,
|
|
178
|
+
* and both the tutor and the panel read it from here instead of guessing.
|
|
179
|
+
*
|
|
180
|
+
* There is deliberately no `progress` field. A focus is a pointer, not a
|
|
181
|
+
* measure; how far along the learner is lives in the node's state and evidence.
|
|
182
|
+
*/
|
|
183
|
+
export declare const FOCUS_STATUSES: readonly ["active", "ended"];
|
|
184
|
+
export declare const FocusStatusSchema: z.ZodEnum<{
|
|
185
|
+
active: "active";
|
|
186
|
+
ended: "ended";
|
|
187
|
+
}>;
|
|
188
|
+
export type FocusStatus = z.infer<typeof FocusStatusSchema>;
|
|
189
|
+
export declare const FocusSchema: z.ZodObject<{
|
|
190
|
+
courseId: z.ZodString;
|
|
191
|
+
nodeId: z.ZodString;
|
|
192
|
+
startedAt: z.ZodString;
|
|
193
|
+
status: z.ZodEnum<{
|
|
194
|
+
active: "active";
|
|
195
|
+
ended: "ended";
|
|
196
|
+
}>;
|
|
197
|
+
updatedAt: z.ZodString;
|
|
198
|
+
endedAt: z.ZodOptional<z.ZodString>;
|
|
199
|
+
nextStepId: z.ZodOptional<z.ZodString>;
|
|
200
|
+
}, z.core.$strip>;
|
|
201
|
+
export type FocusRecord = z.infer<typeof FocusSchema>;
|
|
202
|
+
export type FocusKey = string;
|
|
203
|
+
/**
|
|
204
|
+
* The tutor's decision about where the learner should go after this node.
|
|
205
|
+
*
|
|
206
|
+
* `action` is one of the skill's six readiness outcomes, reused rather than
|
|
207
|
+
* re-invented: the words for "what this concept showed" and "where that sends
|
|
208
|
+
* the learner" are the same words. See `vocabulary.ts` for what each one
|
|
209
|
+
* implies about a target.
|
|
210
|
+
*
|
|
211
|
+
* `targetNodeId` absent means **stay here**. That is the only encoding of
|
|
212
|
+
* "stay" — a named target is always a move — so the runtime never has to guess
|
|
213
|
+
* what a decision meant.
|
|
214
|
+
*
|
|
215
|
+
* `reason` is required and is written for the learner: the panel shows it
|
|
216
|
+
* verbatim, which is what makes the recommendation explicable instead of
|
|
217
|
+
* mysterious.
|
|
218
|
+
*/
|
|
219
|
+
export declare const NextStepSchema: z.ZodObject<{
|
|
220
|
+
fromNodeId: z.ZodString;
|
|
221
|
+
courseId: z.ZodString;
|
|
222
|
+
action: z.ZodEnum<{
|
|
223
|
+
advance: "advance";
|
|
224
|
+
"advance-with-caution": "advance-with-caution";
|
|
225
|
+
"review-first": "review-first";
|
|
226
|
+
"step-down": "step-down";
|
|
227
|
+
"diagnose-again": "diagnose-again";
|
|
228
|
+
"more-practice": "more-practice";
|
|
229
|
+
}>;
|
|
230
|
+
targetNodeId: z.ZodOptional<z.ZodString>;
|
|
231
|
+
reason: z.ZodString;
|
|
232
|
+
createdAt: z.ZodString;
|
|
233
|
+
}, z.core.$strip>;
|
|
234
|
+
export type NextStepRecord = z.infer<typeof NextStepSchema>;
|
|
235
|
+
export type NextStepKey = string;
|
|
236
|
+
/**
|
|
237
|
+
* Identifies the document, so a file found on a disk years later explains
|
|
238
|
+
* itself without this project having to be installed.
|
|
239
|
+
*/
|
|
240
|
+
export declare const EXPORT_FORMAT = "dsh-diagnostic-tutor/state";
|
|
241
|
+
export declare const EXPORT_VERSION = 1;
|
|
242
|
+
/**
|
|
243
|
+
* Everything the learner owns.
|
|
244
|
+
*
|
|
245
|
+
* Plain data, no handles and no methods: an export that needed this plugin to
|
|
246
|
+
* read it would not be an export. `format` and `version` are first so the file
|
|
247
|
+
* is self-describing, and there is no `handoffs` key on purpose — a handoff is
|
|
248
|
+
* operational timing for a wait in progress, not learning state.
|
|
249
|
+
*/
|
|
250
|
+
export interface UdExport {
|
|
251
|
+
readonly format: typeof EXPORT_FORMAT;
|
|
252
|
+
readonly version: number;
|
|
253
|
+
readonly exportedAt: string;
|
|
254
|
+
readonly domain: {
|
|
255
|
+
readonly name: string;
|
|
256
|
+
readonly version: number;
|
|
257
|
+
};
|
|
258
|
+
readonly learner: LearnerProfile;
|
|
259
|
+
readonly courses: readonly CourseRecord[];
|
|
260
|
+
readonly nodes: readonly NodeRecord[];
|
|
261
|
+
readonly lessons: readonly LessonRecord[];
|
|
262
|
+
readonly nextSteps: readonly NextStepRecord[];
|
|
263
|
+
readonly focus: readonly FocusRecord[];
|
|
264
|
+
}
|
|
265
|
+
export type CourseKey = string;
|
|
266
|
+
export type NodeKey = string;
|
|
267
|
+
/** Domain name. Must match the storage hub's `UNIT_NAME_RE` (`^[a-z][a-z0-9_]*$`). */
|
|
268
|
+
export declare const UDT_DOMAIN_NAME = "udt";
|
|
269
|
+
/**
|
|
270
|
+
* Still 1, and that is a deliberate finding rather than an oversight.
|
|
271
|
+
*
|
|
272
|
+
* v0.0.3 added the `nodes` table. That is **additive**: a v1 document simply
|
|
273
|
+
* has no `nodes` map, and the facility builds its table set from the spec, so
|
|
274
|
+
* an old document opens with an empty map.
|
|
275
|
+
*
|
|
276
|
+
* The version must NOT be bumped for an additive change, because the `single`
|
|
277
|
+
* layout enforces it strictly: `dsh-storage-json`'s `openSingleUnit` rejects a
|
|
278
|
+
* document whose stamped version differs from the spec before any compatibility
|
|
279
|
+
* list is consulted (`StorageError: unit 'udt': stored version 1 != expected 2`,
|
|
280
|
+
* `code: 'version-mismatch'`). `compatibleVersions` is honoured by `per-record`
|
|
281
|
+
* backends only. Bumping here would make every existing store unopenable —
|
|
282
|
+
* an outage in exchange for nothing.
|
|
283
|
+
*
|
|
284
|
+
* So: bump this only when a stored *record* can no longer be read as-is, and
|
|
285
|
+
* ship a migration in the same release.
|
|
286
|
+
*/
|
|
287
|
+
export declare const UDT_DOMAIN_VERSION = 1;
|
|
288
|
+
export declare const COURSES_TABLE = "courses";
|
|
289
|
+
export declare const NODES_TABLE = "nodes";
|
|
290
|
+
export declare const LESSONS_TABLE = "lessons";
|
|
291
|
+
export declare const FOCUS_TABLE = "focus";
|
|
292
|
+
export declare const NEXT_STEPS_TABLE = "next_steps";
|
|
293
|
+
export declare const HANDOFFS_TABLE = "handoffs";
|
|
294
|
+
/** Sentinel meaning "the global slot has never been written". */
|
|
295
|
+
export declare const UNINITIALIZED = "";
|
|
296
|
+
export declare const udtDomain: {
|
|
297
|
+
name: string;
|
|
298
|
+
version: number;
|
|
299
|
+
global: {
|
|
300
|
+
schema: z.ZodObject<{
|
|
301
|
+
preferredLanguage: z.ZodOptional<z.ZodString>;
|
|
302
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
303
|
+
auto: "auto";
|
|
304
|
+
"zero-base": "zero-base";
|
|
305
|
+
standard: "standard";
|
|
306
|
+
advanced: "advanced";
|
|
307
|
+
}>>;
|
|
308
|
+
activeCourseId: z.ZodOptional<z.ZodString>;
|
|
309
|
+
initializedAt: z.ZodString;
|
|
310
|
+
updatedAt: z.ZodString;
|
|
311
|
+
}, z.core.$strip>;
|
|
312
|
+
initial: {
|
|
313
|
+
initializedAt: string;
|
|
314
|
+
updatedAt: string;
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
tables: {
|
|
318
|
+
courses: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
319
|
+
id: string;
|
|
320
|
+
title: string;
|
|
321
|
+
goal: string;
|
|
322
|
+
status: "active" | "paused" | "archived";
|
|
323
|
+
createdAt: string;
|
|
324
|
+
updatedAt: string;
|
|
325
|
+
}>;
|
|
326
|
+
nodes: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
327
|
+
id: string;
|
|
328
|
+
courseId: string;
|
|
329
|
+
title: string;
|
|
330
|
+
relation: "goal" | "part-of" | "prerequisite" | "related";
|
|
331
|
+
state: "unconfirmed" | "explained" | "practiced" | "checked" | "weak" | "blocked" | "confirmed";
|
|
332
|
+
evidence: {
|
|
333
|
+
kind: "goal-stated" | "diagnosis" | "explanation" | "practice" | "check" | "transfer";
|
|
334
|
+
at: string;
|
|
335
|
+
note?: string | undefined;
|
|
336
|
+
readiness?: "advance" | "advance-with-caution" | "review-first" | "step-down" | "diagnose-again" | "more-practice" | undefined;
|
|
337
|
+
}[];
|
|
338
|
+
createdAt: string;
|
|
339
|
+
updatedAt: string;
|
|
340
|
+
parentId?: string | undefined;
|
|
341
|
+
}>;
|
|
342
|
+
lessons: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
343
|
+
id: string;
|
|
344
|
+
courseId: string;
|
|
345
|
+
nodeId: string;
|
|
346
|
+
title: string;
|
|
347
|
+
blocks: ({
|
|
348
|
+
type: "text";
|
|
349
|
+
content: {
|
|
350
|
+
md: string;
|
|
351
|
+
};
|
|
352
|
+
id: string;
|
|
353
|
+
metadata?: Record<string, unknown> | undefined;
|
|
354
|
+
} | {
|
|
355
|
+
type: "example";
|
|
356
|
+
content: {
|
|
357
|
+
title: string;
|
|
358
|
+
steps: string[];
|
|
359
|
+
takeaway?: string | undefined;
|
|
360
|
+
};
|
|
361
|
+
id: string;
|
|
362
|
+
metadata?: Record<string, unknown> | undefined;
|
|
363
|
+
} | {
|
|
364
|
+
type: "diagram";
|
|
365
|
+
content: {
|
|
366
|
+
format: "ascii" | "mermaid";
|
|
367
|
+
spec: string;
|
|
368
|
+
caption?: string | undefined;
|
|
369
|
+
};
|
|
370
|
+
id: string;
|
|
371
|
+
metadata?: Record<string, unknown> | undefined;
|
|
372
|
+
} | {
|
|
373
|
+
type: "check";
|
|
374
|
+
content: {
|
|
375
|
+
prompt: string;
|
|
376
|
+
expect?: "reasoning" | "answer" | undefined;
|
|
377
|
+
hint?: string | undefined;
|
|
378
|
+
};
|
|
379
|
+
id: string;
|
|
380
|
+
metadata?: Record<string, unknown> | undefined;
|
|
381
|
+
})[];
|
|
382
|
+
origin: "prototype" | "tutor";
|
|
383
|
+
createdAt: string;
|
|
384
|
+
updatedAt: string;
|
|
385
|
+
}>;
|
|
386
|
+
focus: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
387
|
+
courseId: string;
|
|
388
|
+
nodeId: string;
|
|
389
|
+
startedAt: string;
|
|
390
|
+
status: "active" | "ended";
|
|
391
|
+
updatedAt: string;
|
|
392
|
+
endedAt?: string | undefined;
|
|
393
|
+
nextStepId?: string | undefined;
|
|
394
|
+
}>;
|
|
395
|
+
next_steps: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
396
|
+
fromNodeId: string;
|
|
397
|
+
courseId: string;
|
|
398
|
+
action: "advance" | "advance-with-caution" | "review-first" | "step-down" | "diagnose-again" | "more-practice";
|
|
399
|
+
reason: string;
|
|
400
|
+
createdAt: string;
|
|
401
|
+
targetNodeId?: string | undefined;
|
|
402
|
+
}>;
|
|
403
|
+
handoffs: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
|
|
404
|
+
targetNodeId: string;
|
|
405
|
+
courseId: string;
|
|
406
|
+
fromNodeId: string;
|
|
407
|
+
status: "requested" | "prompted" | "working" | "ready" | "failed";
|
|
408
|
+
attempts: number;
|
|
409
|
+
requestedAt: string;
|
|
410
|
+
updatedAt: string;
|
|
411
|
+
sessionId?: string | undefined;
|
|
412
|
+
focusRecordedAt?: string | undefined;
|
|
413
|
+
promptedAt?: string | undefined;
|
|
414
|
+
firstActivityAt?: string | undefined;
|
|
415
|
+
lessonAt?: string | undefined;
|
|
416
|
+
observedAt?: string | undefined;
|
|
417
|
+
failedAt?: string | undefined;
|
|
418
|
+
failureReason?: string | undefined;
|
|
419
|
+
}>;
|
|
420
|
+
};
|
|
421
|
+
};
|
|
422
|
+
export type UdtDomain = typeof udtDomain;
|
|
423
|
+
/** Read-only diagnostics for the `udt_status` tool and for tests. */
|
|
424
|
+
export interface UdStateSnapshot {
|
|
425
|
+
readonly domain: string;
|
|
426
|
+
readonly version: number;
|
|
427
|
+
/** Whether the global slot holds a written profile (false ⇒ never initialized). */
|
|
428
|
+
readonly initialized: boolean;
|
|
429
|
+
readonly learner: LearnerProfile;
|
|
430
|
+
readonly courseCount: number;
|
|
431
|
+
readonly nodeCount: number;
|
|
432
|
+
readonly lessonCount: number;
|
|
433
|
+
readonly courses: readonly {
|
|
434
|
+
id: string;
|
|
435
|
+
title: string;
|
|
436
|
+
status: CourseStatus;
|
|
437
|
+
}[];
|
|
438
|
+
}
|
|
439
|
+
/** The map for one course, as returned by `udt_map_get`. */
|
|
440
|
+
export interface CourseMap {
|
|
441
|
+
readonly course: CourseRecord;
|
|
442
|
+
readonly nodes: readonly NodeRecord[];
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* The plugin's whole persistence surface.
|
|
446
|
+
*
|
|
447
|
+
* Nothing outside this module touches the `Domain` handle, so changing the
|
|
448
|
+
* storage layout later is a change in one file. Every write returns the stored
|
|
449
|
+
* record so callers never have to re-read.
|
|
450
|
+
*/
|
|
451
|
+
export interface UdState {
|
|
452
|
+
readonly name: string;
|
|
453
|
+
readonly version: number;
|
|
454
|
+
/** Synchronous read of the learner singleton. */
|
|
455
|
+
readLearner(): LearnerProfile;
|
|
456
|
+
/** Whether the learner singleton has ever been written. */
|
|
457
|
+
isInitialized(): boolean;
|
|
458
|
+
/**
|
|
459
|
+
* Write the learner singleton on first open, and do nothing on later opens.
|
|
460
|
+
* @param now - ISO timestamp supplied by the caller so the write is testable.
|
|
461
|
+
*/
|
|
462
|
+
ensureLearner(now: string): Promise<LearnerProfile>;
|
|
463
|
+
/**
|
|
464
|
+
* Merge a patch into the learner singleton and write it durably.
|
|
465
|
+
* @param patch - fields to overwrite; omitted fields are preserved.
|
|
466
|
+
* @param now - ISO timestamp for `updatedAt`.
|
|
467
|
+
*/
|
|
468
|
+
updateLearner(patch: Partial<Omit<LearnerProfile, 'initializedAt' | 'updatedAt'>>, now: string): Promise<LearnerProfile>;
|
|
469
|
+
listCourses(): CourseRecord[];
|
|
470
|
+
readCourse(id: CourseKey): CourseRecord | undefined;
|
|
471
|
+
/** Insert or fully replace one course. */
|
|
472
|
+
writeCourse(record: CourseRecord): Promise<CourseRecord>;
|
|
473
|
+
/**
|
|
474
|
+
* Make one course active: it becomes `active`, every other course that was
|
|
475
|
+
* active becomes `paused`, and the learner's `activeCourseId` points at it.
|
|
476
|
+
*
|
|
477
|
+
* Only one goal is in focus at a time. Pausing is reversible — the other
|
|
478
|
+
* courses keep their records and all of their nodes.
|
|
479
|
+
*
|
|
480
|
+
* @param courseId - the course to focus.
|
|
481
|
+
* @param now - ISO timestamp.
|
|
482
|
+
* @returns the activated course.
|
|
483
|
+
*/
|
|
484
|
+
activateCourse(courseId: CourseKey, now: string): Promise<CourseRecord>;
|
|
485
|
+
/** Every node of one course, in insertion order. */
|
|
486
|
+
listNodes(courseId: CourseKey): NodeRecord[];
|
|
487
|
+
readNode(id: NodeKey): NodeRecord | undefined;
|
|
488
|
+
/** Insert or fully replace one node. */
|
|
489
|
+
writeNode(record: NodeRecord): Promise<NodeRecord>;
|
|
490
|
+
/** Number of nodes across every course. */
|
|
491
|
+
nodeCount(): number;
|
|
492
|
+
/** The course plus its map. */
|
|
493
|
+
readMap(courseId: CourseKey): CourseMap | undefined;
|
|
494
|
+
/** The recorded focus for one course, if any. */
|
|
495
|
+
readFocus(courseId: CourseKey): FocusRecord | undefined;
|
|
496
|
+
/**
|
|
497
|
+
* Record that learning is starting on one node of one course.
|
|
498
|
+
*
|
|
499
|
+
* Fails loudly when the course or the node does not exist, or when the node
|
|
500
|
+
* belongs to another course — a focus pointing at nothing would leave the
|
|
501
|
+
* tutor teaching a node the map does not have.
|
|
502
|
+
*
|
|
503
|
+
* @param courseId - the course.
|
|
504
|
+
* @param nodeId - the node to focus.
|
|
505
|
+
* @param now - ISO timestamp.
|
|
506
|
+
* @returns the stored focus.
|
|
507
|
+
*/
|
|
508
|
+
startFocus(courseId: CourseKey, nodeId: NodeKey, now: string): Promise<FocusRecord>;
|
|
509
|
+
/** Mark the course's focus as ended. No-op when there is none. */
|
|
510
|
+
endFocus(courseId: CourseKey, now: string): Promise<void>;
|
|
511
|
+
/**
|
|
512
|
+
* Record the tutor's decision about where to go next.
|
|
513
|
+
*
|
|
514
|
+
* This is the one place the focus lifecycle turns over: a decision that names
|
|
515
|
+
* a target ends the focus and links the recommendation to it; a decision that
|
|
516
|
+
* does not leaves the focus active, because the learner has not moved.
|
|
517
|
+
*
|
|
518
|
+
* The runtime validates the *shape* of the decision — the nodes must exist,
|
|
519
|
+
* belong to the course, and match what the action implies — and never invents
|
|
520
|
+
* a target. Choosing where to go is the tutor's.
|
|
521
|
+
*
|
|
522
|
+
* @param input - the decision.
|
|
523
|
+
* @returns the stored recommendation and the focus after the decision.
|
|
524
|
+
*/
|
|
525
|
+
decideNext(input: {
|
|
526
|
+
courseId: CourseKey;
|
|
527
|
+
fromNodeId: NodeKey;
|
|
528
|
+
action: Readiness;
|
|
529
|
+
targetNodeId?: NodeKey;
|
|
530
|
+
reason: string;
|
|
531
|
+
now: string;
|
|
532
|
+
}): Promise<{
|
|
533
|
+
nextStep: NextStepRecord;
|
|
534
|
+
focus: FocusRecord;
|
|
535
|
+
}>;
|
|
536
|
+
/** The most recent recommendation recorded for a course, if any. */
|
|
537
|
+
latestNextStep(courseId: CourseKey): NextStepRecord | undefined;
|
|
538
|
+
/** A recommendation by key. */
|
|
539
|
+
readNextStep(id: NextStepKey): NextStepRecord | undefined;
|
|
540
|
+
/** Every recommendation, for export. */
|
|
541
|
+
listNextSteps(): NextStepRecord[];
|
|
542
|
+
/** Every lesson, for export. */
|
|
543
|
+
listLessons(): LessonRecord[];
|
|
544
|
+
/** Every focus, for export. */
|
|
545
|
+
listFocus(): FocusRecord[];
|
|
546
|
+
/**
|
|
547
|
+
* Everything the learner owns, as one plain document.
|
|
548
|
+
*
|
|
549
|
+
* Handoffs are deliberately **not** included: they are operational timing
|
|
550
|
+
* for a wait in progress, not learning state, and restoring them would mean
|
|
551
|
+
* restoring a claim about a model turn that is no longer running.
|
|
552
|
+
*/
|
|
553
|
+
exportState(now: string): UdExport;
|
|
554
|
+
/**
|
|
555
|
+
* Delete everything and return to first-run.
|
|
556
|
+
*
|
|
557
|
+
* Irreversible by design — an undo would mean keeping a copy of what the
|
|
558
|
+
* learner asked to delete, which is the opposite of the point.
|
|
559
|
+
*/
|
|
560
|
+
resetState(now: string): Promise<void>;
|
|
561
|
+
readHandoff(targetNodeId: HandoffKey): HandoffRecord | undefined;
|
|
562
|
+
/** Insert or replace one handoff. */
|
|
563
|
+
writeHandoff(record: HandoffRecord): Promise<HandoffRecord>;
|
|
564
|
+
/**
|
|
565
|
+
* Apply a transition atomically.
|
|
566
|
+
*
|
|
567
|
+
* Two writers touch a handoff concurrently in normal operation — the
|
|
568
|
+
* first-activity listener and the tool that writes a lesson — and a plain
|
|
569
|
+
* read-modify-write loses one of them. The domain's `update` runs the
|
|
570
|
+
* transform on its single write chain, so the transitions serialise.
|
|
571
|
+
*
|
|
572
|
+
* @param targetNodeId - the handoff.
|
|
573
|
+
* @param transform - pure transform from current to next.
|
|
574
|
+
* @returns the stored record.
|
|
575
|
+
*/
|
|
576
|
+
updateHandoff(targetNodeId: HandoffKey, transform: (record: HandoffRecord) => HandoffRecord): Promise<HandoffRecord>;
|
|
577
|
+
/** The handoff for whichever node is currently focused, if any. */
|
|
578
|
+
activeHandoff(): HandoffRecord | undefined;
|
|
579
|
+
/** Every handoff, for diagnostics and tests. */
|
|
580
|
+
listHandoffs(): HandoffRecord[];
|
|
581
|
+
/** The focus of the learner's active course, joined with its course and node. */
|
|
582
|
+
activeFocus(): {
|
|
583
|
+
focus: FocusRecord;
|
|
584
|
+
course: CourseRecord;
|
|
585
|
+
node: NodeRecord;
|
|
586
|
+
} | undefined;
|
|
587
|
+
readLesson(id: LessonKey): LessonRecord | undefined;
|
|
588
|
+
/** The lesson already stored for a node, if any. */
|
|
589
|
+
lessonForNode(nodeId: NodeKey): LessonRecord | undefined;
|
|
590
|
+
/** Insert or fully replace one lesson. */
|
|
591
|
+
writeLesson(record: LessonRecord): Promise<LessonRecord>;
|
|
592
|
+
/** Number of lessons across every course. */
|
|
593
|
+
lessonCount(): number;
|
|
594
|
+
snapshot(): UdStateSnapshot;
|
|
595
|
+
/** Release the backend unit. Idempotent. */
|
|
596
|
+
close(): Promise<void>;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Build a fresh node in its born state.
|
|
600
|
+
*
|
|
601
|
+
* Kept here rather than in the tool layer so the "nothing is born confirmed"
|
|
602
|
+
* rule has exactly one implementation.
|
|
603
|
+
*
|
|
604
|
+
* @param input - the fields the caller supplies.
|
|
605
|
+
* @returns a complete, valid record.
|
|
606
|
+
*/
|
|
607
|
+
export declare function newNode(input: {
|
|
608
|
+
id: string;
|
|
609
|
+
courseId: string;
|
|
610
|
+
title: string;
|
|
611
|
+
relation: NodeRelation;
|
|
612
|
+
parentId?: string;
|
|
613
|
+
state?: NodeState;
|
|
614
|
+
evidence?: Evidence[];
|
|
615
|
+
now: string;
|
|
616
|
+
}): NodeRecord;
|
|
617
|
+
/**
|
|
618
|
+
* Open the plugin's domain over the host's facility.
|
|
619
|
+
*
|
|
620
|
+
* The caller owns the returned handle and must `close()` it — see `apply`,
|
|
621
|
+
* which does so from a `ctx.effect` disposer so an unload leaves no residue.
|
|
622
|
+
*
|
|
623
|
+
* @param facility - the `storageDomain` service taken from `ctx`.
|
|
624
|
+
* @returns the open handle.
|
|
625
|
+
*/
|
|
626
|
+
export declare function openUdState(facility: DomainFacility): Promise<UdState>;
|
|
627
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing tools.
|
|
3
|
+
*
|
|
4
|
+
* v0.0.3 registers four, and the restraint is the architecture: this plugin
|
|
5
|
+
* owns **state, artifacts and presentation**, while every teaching decision
|
|
6
|
+
* belongs to the Universal Diagnostic Tutor skill. So each tool here either
|
|
7
|
+
* records what was observed or reports what is stored. None of them decides
|
|
8
|
+
* what to teach, how to explain it, or when to advance.
|
|
9
|
+
*
|
|
10
|
+
* That is also why the rules in `diagnosis.ts` are enforced *here* rather than
|
|
11
|
+
* negotiated with the caller: the runtime's job is to make unverified mastery
|
|
12
|
+
* and curriculum dumps impossible to store, and then get out of the way.
|
|
13
|
+
*
|
|
14
|
+
* As in `state.ts`, `defineTool` is a *pure builder* (it compiles the parameter
|
|
15
|
+
* DSL into JSON Schema and returns a plain descriptor), so it is
|
|
16
|
+
* value-imported. The registry itself is taken from `ctx`.
|
|
17
|
+
*/
|
|
18
|
+
import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
|
|
19
|
+
import type { UdState } from './state.js';
|
|
20
|
+
/**
|
|
21
|
+
* The slice of `ctx` this module needs.
|
|
22
|
+
*
|
|
23
|
+
* Declared structurally on purpose: we depend on the *shape* of the tools
|
|
24
|
+
* registry, not on a class we might `instanceof` across harness cohorts.
|
|
25
|
+
*/
|
|
26
|
+
export interface ToolsHost {
|
|
27
|
+
tools: {
|
|
28
|
+
register(definition: ToolDefinition): unknown;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register this plugin's tools on the host's registry.
|
|
33
|
+
*
|
|
34
|
+
* @param host - the context slice carrying the tools registry.
|
|
35
|
+
* @param state - the open persistence handle the tools read from and write to.
|
|
36
|
+
*/
|
|
37
|
+
export declare function registerTools(host: ToolsHost, state: UdState): void;
|
|
38
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAe5D,OAAO,KAAK,EAAwB,OAAO,EAAE,MAAM,YAAY,CAAA;AAU/D;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAAA;KAAE,CAAA;CACzD;AA+iCD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAOnE"}
|