dsh-diagnostic-tutor 0.1.0 → 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 +316 -79
- package/lib/api.js +364 -78
- 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 +9952 -821
- package/lib/client.js.map +1 -1
- package/lib/diagnostics.js +170 -0
- package/lib/diagnostics.js.map +1 -0
- package/lib/execution-key.js +91 -0
- package/lib/execution-key.js.map +1 -0
- package/lib/handoff.js +44 -1
- package/lib/handoff.js.map +1 -1
- package/lib/index.js +87 -51
- 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 +353 -47
- package/lib/state.js.map +1 -1
- package/lib/tools.js +620 -123
- package/lib/tools.js.map +1 -1
- package/lib/types/api.d.ts +10 -3
- 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 +81 -7
- 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/execution-key.d.ts +59 -0
- package/lib/types/execution-key.d.ts.map +1 -0
- package/lib/types/handoff.d.ts +2 -2
- package/lib/types/handoff.d.ts.map +1 -1
- package/lib/types/index.d.ts +19 -14
- 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 +607 -23
- 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/udt.d.ts +20 -24
- package/lib/types/udt.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/udt.js +72 -19
- package/lib/udt.js.map +1 -1
- package/lib/version.js +26 -0
- package/lib/version.js.map +1 -0
- package/package.json +27 -22
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** Model-facing review queue. Scheduling only; no mastery judgement. */
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
5
|
+
import { MAX_REVIEW_CARDS, REVIEW_RATINGS, dueCards, scheduleReview, } from './review.js';
|
|
6
|
+
const ReviewInputSchema = z.object({
|
|
7
|
+
front: z.string().min(1).max(2000),
|
|
8
|
+
back: z.string().min(1).max(4000),
|
|
9
|
+
courseId: z.string().min(1).max(120).optional(),
|
|
10
|
+
nodeId: z.string().min(1).max(120).optional(),
|
|
11
|
+
blockId: z.string().min(1).max(120).optional(),
|
|
12
|
+
sourceRefs: z.array(z.object({ sourceId: z.string().min(1).max(120), locator: z.string().min(1).max(300) })).max(6).optional(),
|
|
13
|
+
}).strict();
|
|
14
|
+
function output() {
|
|
15
|
+
return { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }] };
|
|
16
|
+
}
|
|
17
|
+
function validate(state, raw, index) {
|
|
18
|
+
const input = ReviewInputSchema.parse(raw);
|
|
19
|
+
if (input.courseId !== undefined) {
|
|
20
|
+
if (state.readCourse(input.courseId) === undefined)
|
|
21
|
+
throw new Error(`card[${index}] references an unknown course`);
|
|
22
|
+
if (input.nodeId !== undefined && state.readNode(input.nodeId)?.courseId !== input.courseId)
|
|
23
|
+
throw new Error(`card[${index}] references a node outside the course`);
|
|
24
|
+
}
|
|
25
|
+
else if (input.nodeId !== undefined)
|
|
26
|
+
throw new Error(`card[${index}] cannot name a node without its course`);
|
|
27
|
+
for (const ref of input.sourceRefs ?? []) {
|
|
28
|
+
if (state.readSource(ref.sourceId) === undefined)
|
|
29
|
+
throw new Error(`card[${index}] references an unknown source`);
|
|
30
|
+
}
|
|
31
|
+
return input;
|
|
32
|
+
}
|
|
33
|
+
export function reviewTools(state) {
|
|
34
|
+
return [
|
|
35
|
+
defineTool({
|
|
36
|
+
name: 'udt_review_add',
|
|
37
|
+
description: 'Add review cards to the learner-owned spaced-repetition queue. Scheduling is runtime policy, not a mastery claim: no node state changes. ' +
|
|
38
|
+
'Use a flashcard or a check as the source of a card; include sourceRefs when the card quotes a source. New cards are due immediately.',
|
|
39
|
+
parameters: {
|
|
40
|
+
cards: {
|
|
41
|
+
type: 'array', required: true,
|
|
42
|
+
items: {
|
|
43
|
+
type: 'object', additionalProperties: false,
|
|
44
|
+
properties: {
|
|
45
|
+
front: { type: 'string', required: true },
|
|
46
|
+
back: { type: 'string', required: true },
|
|
47
|
+
courseId: { type: 'string' },
|
|
48
|
+
nodeId: { type: 'string' },
|
|
49
|
+
blockId: { type: 'string' },
|
|
50
|
+
sourceRefs: { type: 'array', items: { type: 'object', additionalProperties: false, properties: { sourceId: { type: 'string', required: true }, locator: { type: 'string', required: true } } } },
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
output: output(),
|
|
56
|
+
execute: async (args) => {
|
|
57
|
+
const input = args;
|
|
58
|
+
if (!Array.isArray(input.cards) || input.cards.length === 0)
|
|
59
|
+
throw new Error('review-add-needs-cards');
|
|
60
|
+
if (state.listReviewCards().length + input.cards.length > MAX_REVIEW_CARDS)
|
|
61
|
+
throw new Error('too-many-review-cards');
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
const cards = input.cards.map((candidate, index) => {
|
|
64
|
+
const parsed = validate(state, candidate, index);
|
|
65
|
+
return {
|
|
66
|
+
id: randomUUID(), front: parsed.front, back: parsed.back,
|
|
67
|
+
dueAt: now, intervalDays: 0, ease: 2.5, reps: 0, lapses: 0, status: 'open', createdAt: now, updatedAt: now,
|
|
68
|
+
...(parsed.courseId === undefined ? {} : { courseId: parsed.courseId }),
|
|
69
|
+
...(parsed.nodeId === undefined ? {} : { nodeId: parsed.nodeId }),
|
|
70
|
+
...(parsed.blockId === undefined ? {} : { blockId: parsed.blockId }),
|
|
71
|
+
...(parsed.sourceRefs === undefined ? {} : { sourceRefs: parsed.sourceRefs }),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
for (const card of cards)
|
|
75
|
+
await state.writeReviewCard(card);
|
|
76
|
+
return JSON.parse(JSON.stringify({ ok: true, cards }));
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
defineTool({
|
|
80
|
+
name: 'udt_review_next',
|
|
81
|
+
description: 'Read the review cards that are due now (open, dueAt <= now), earliest first. This only reports the queue; it does not grade or change learning state.',
|
|
82
|
+
parameters: { limit: { type: 'integer', description: 'Maximum cards, 1-20; default 5.' } },
|
|
83
|
+
output: output(),
|
|
84
|
+
execute: async (args) => {
|
|
85
|
+
const raw = args.limit;
|
|
86
|
+
const limit = Number.isInteger(raw) ? Math.min(20, Math.max(1, raw)) : 5;
|
|
87
|
+
return JSON.parse(JSON.stringify({ now: new Date().toISOString(), cards: dueCards(state.listReviewCards()).slice(0, limit) }));
|
|
88
|
+
},
|
|
89
|
+
}),
|
|
90
|
+
defineTool({
|
|
91
|
+
name: 'udt_review_grade',
|
|
92
|
+
description: 'Record one review grade (again | hard | good | easy) and schedule the card. This is interval arithmetic only: it does not mark a node confirmed, does not complete a lesson and does not auto-advance.',
|
|
93
|
+
parameters: {
|
|
94
|
+
cardId: { type: 'string', required: true },
|
|
95
|
+
rating: { type: 'string', required: true, enum: [...REVIEW_RATINGS] },
|
|
96
|
+
},
|
|
97
|
+
output: output(),
|
|
98
|
+
execute: async (args) => {
|
|
99
|
+
const input = args;
|
|
100
|
+
if (input.cardId === undefined)
|
|
101
|
+
throw new Error('review-grade-needs-cardId');
|
|
102
|
+
if (input.rating === undefined || !REVIEW_RATINGS.includes(input.rating))
|
|
103
|
+
throw new Error('review-grade-needs-rating');
|
|
104
|
+
const card = state.readReviewCard(input.cardId);
|
|
105
|
+
if (card === undefined)
|
|
106
|
+
throw new Error('no-such-review-card: read udt_review_next');
|
|
107
|
+
const { card: updated, log } = scheduleReview(card, input.rating);
|
|
108
|
+
await state.writeReviewCard(updated);
|
|
109
|
+
await state.writeReviewLog(log);
|
|
110
|
+
return JSON.parse(JSON.stringify({ ok: true, card: updated, log }));
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=review-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-tools.js","sourceRoot":"","sources":["../src/review-tools.ts"],"names":[],"mappings":"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"}
|
package/lib/review.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** Review cards and a dependency-free local interval scheduler. No mastery claims. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const REVIEW_CARDS_TABLE = 'review_cards';
|
|
4
|
+
export const REVIEW_LOG_TABLE = 'review_log';
|
|
5
|
+
export const REVIEW_RATINGS = ['again', 'hard', 'good', 'easy'];
|
|
6
|
+
export const REVIEW_STATUSES = ['open', 'suspended'];
|
|
7
|
+
export const MAX_REVIEW_CARDS = 500;
|
|
8
|
+
export const MAX_REVIEW_FRONT_CHARS = 2000;
|
|
9
|
+
export const MAX_REVIEW_BACK_CHARS = 4000;
|
|
10
|
+
export const ReviewSourceRefSchema = z.object({
|
|
11
|
+
sourceId: z.string().min(1).max(120),
|
|
12
|
+
locator: z.string().min(1).max(300),
|
|
13
|
+
}).strict();
|
|
14
|
+
export const ReviewCardSchema = z.object({
|
|
15
|
+
id: z.string().min(1).max(120),
|
|
16
|
+
courseId: z.string().min(1).max(120).optional(),
|
|
17
|
+
nodeId: z.string().min(1).max(120).optional(),
|
|
18
|
+
blockId: z.string().min(1).max(120).optional(),
|
|
19
|
+
front: z.string().min(1).max(MAX_REVIEW_FRONT_CHARS),
|
|
20
|
+
back: z.string().min(1).max(MAX_REVIEW_BACK_CHARS),
|
|
21
|
+
sourceRefs: z.array(ReviewSourceRefSchema).max(6).optional(),
|
|
22
|
+
dueAt: z.string(),
|
|
23
|
+
/** Days; fractional values are allowed for the first "again" step. */
|
|
24
|
+
intervalDays: z.number().min(0).max(3650),
|
|
25
|
+
ease: z.number().min(1.3).max(3.2),
|
|
26
|
+
reps: z.number().int().min(0),
|
|
27
|
+
lapses: z.number().int().min(0),
|
|
28
|
+
status: z.enum(REVIEW_STATUSES),
|
|
29
|
+
createdAt: z.string(),
|
|
30
|
+
updatedAt: z.string(),
|
|
31
|
+
}).strict();
|
|
32
|
+
export const ReviewLogSchema = z.object({
|
|
33
|
+
id: z.string().min(1).max(120),
|
|
34
|
+
cardId: z.string().min(1).max(120),
|
|
35
|
+
rating: z.enum(REVIEW_RATINGS),
|
|
36
|
+
at: z.string(),
|
|
37
|
+
previousDue: z.string(),
|
|
38
|
+
nextDue: z.string(),
|
|
39
|
+
intervalDays: z.number().min(0),
|
|
40
|
+
ease: z.number().min(1.3).max(3.2),
|
|
41
|
+
/** Present on logs written by the current build; old logs may lack them. */
|
|
42
|
+
previousIntervalDays: z.number().min(0).optional(),
|
|
43
|
+
previousEase: z.number().min(1.3).max(3.2).optional(),
|
|
44
|
+
previousReps: z.number().int().min(0).optional(),
|
|
45
|
+
previousLapses: z.number().int().min(0).optional(),
|
|
46
|
+
}).strict();
|
|
47
|
+
const DAY_MS = 86_400_000;
|
|
48
|
+
/** Apply one grade. This is scheduling arithmetic, not a judgement about learning. */
|
|
49
|
+
export function scheduleReview(card, rating, now = new Date()) {
|
|
50
|
+
let intervalDays = card.intervalDays;
|
|
51
|
+
let ease = card.ease;
|
|
52
|
+
let lapses = card.lapses;
|
|
53
|
+
if (rating === 'again') {
|
|
54
|
+
intervalDays = 0;
|
|
55
|
+
ease = Math.max(1.3, ease - 0.2);
|
|
56
|
+
lapses += 1;
|
|
57
|
+
}
|
|
58
|
+
else if (rating === 'hard') {
|
|
59
|
+
intervalDays = Math.max(1, card.intervalDays * 1.2);
|
|
60
|
+
ease = Math.max(1.3, ease - 0.15);
|
|
61
|
+
}
|
|
62
|
+
else if (rating === 'good') {
|
|
63
|
+
intervalDays = Math.max(1, card.intervalDays * ease);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
intervalDays = Math.max(2, card.intervalDays * ease * 1.3);
|
|
67
|
+
ease = Math.min(3.2, ease + 0.15);
|
|
68
|
+
}
|
|
69
|
+
const dueAt = rating === 'again'
|
|
70
|
+
? new Date(now.getTime() + 10 * 60_000)
|
|
71
|
+
: new Date(now.getTime() + intervalDays * DAY_MS);
|
|
72
|
+
const updated = {
|
|
73
|
+
...card,
|
|
74
|
+
intervalDays,
|
|
75
|
+
ease,
|
|
76
|
+
lapses,
|
|
77
|
+
reps: card.reps + 1,
|
|
78
|
+
dueAt: dueAt.toISOString(),
|
|
79
|
+
updatedAt: now.toISOString(),
|
|
80
|
+
};
|
|
81
|
+
const log = {
|
|
82
|
+
id: `${card.id}:${now.getTime()}:${card.reps + 1}`,
|
|
83
|
+
cardId: card.id,
|
|
84
|
+
rating,
|
|
85
|
+
at: now.toISOString(),
|
|
86
|
+
previousDue: card.dueAt,
|
|
87
|
+
nextDue: updated.dueAt,
|
|
88
|
+
intervalDays,
|
|
89
|
+
ease,
|
|
90
|
+
previousIntervalDays: card.intervalDays,
|
|
91
|
+
previousEase: card.ease,
|
|
92
|
+
previousReps: card.reps,
|
|
93
|
+
previousLapses: card.lapses,
|
|
94
|
+
};
|
|
95
|
+
return { card: updated, log };
|
|
96
|
+
}
|
|
97
|
+
export function dueCards(cards, now = new Date()) {
|
|
98
|
+
const time = now.getTime();
|
|
99
|
+
return [...cards]
|
|
100
|
+
.filter((card) => card.status === 'open' && Date.parse(card.dueAt) <= time)
|
|
101
|
+
.sort((left, right) => Date.parse(left.dueAt) - Date.parse(right.dueAt));
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Learner-owned source material. Pure schema, no DSH imports. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export const SOURCE_KINDS = ['text', 'file', 'markdown'];
|
|
4
|
+
export const SOURCE_STATUSES = ['ready', 'error'];
|
|
5
|
+
export const MAX_SOURCE_BYTES = 131_072;
|
|
6
|
+
export const MAX_SOURCE_CHARS = MAX_SOURCE_BYTES;
|
|
7
|
+
export const MAX_SOURCES = 40;
|
|
8
|
+
export const MAX_SOURCE_TITLE_CHARS = 200;
|
|
9
|
+
export const MAX_SOURCE_LOCATOR_CHARS = 500;
|
|
10
|
+
export const SourceRecordSchema = z.object({
|
|
11
|
+
id: z.string().min(1).max(120),
|
|
12
|
+
kind: z.enum(SOURCE_KINDS),
|
|
13
|
+
title: z.string().min(1).max(MAX_SOURCE_TITLE_CHARS),
|
|
14
|
+
/** Original path, URL, or a human-readable locator. Never fetched by the plugin. */
|
|
15
|
+
locator: z.string().min(1).max(MAX_SOURCE_LOCATOR_CHARS),
|
|
16
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
17
|
+
bytes: z.number().int().min(0).max(MAX_SOURCE_BYTES),
|
|
18
|
+
createdAt: z.string(),
|
|
19
|
+
status: z.enum(SOURCE_STATUSES),
|
|
20
|
+
/** Extracted text. Optional so an errored future record can stay metadata-only. */
|
|
21
|
+
content: z.string().max(MAX_SOURCE_CHARS).optional(),
|
|
22
|
+
}).strict();
|
|
23
|
+
export const SOURCES_TABLE = 'sources';
|
|
24
|
+
//# sourceMappingURL=source-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-schema.js","sourceRoot":"","sources":["../src/source-schema.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAU,CAAA;AACjE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAA;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAA;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAA;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAA;AAC7B,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA;AACzC,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAE3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACpD,oFAAoF;IACpF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,wBAAwB,CAAC;IACxD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACpD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;IAC/B,mFAAmF;IACnF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC,MAAM,EAAE,CAAA;AAIX,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Model-facing source ingestion: zero network, explicit local file or pasted text. */
|
|
2
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
3
|
+
import { addSource, sourceDraftFromFile, sourceDraftFromText } from './sources.js';
|
|
4
|
+
function output() {
|
|
5
|
+
return { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }] };
|
|
6
|
+
}
|
|
7
|
+
function metadata(record) {
|
|
8
|
+
return { id: record.id, kind: record.kind, title: record.title, locator: record.locator, sha256: record.sha256, bytes: record.bytes, createdAt: record.createdAt, status: record.status };
|
|
9
|
+
}
|
|
10
|
+
export function sourceTools(state) {
|
|
11
|
+
return [
|
|
12
|
+
defineTool({
|
|
13
|
+
name: 'udt_source_add',
|
|
14
|
+
description: 'Add learner-owned source material before teaching from it. Use kind=file with an absolute path to one local .md/.markdown/.txt file, or kind=text/markdown with pasted text. ' +
|
|
15
|
+
'The plugin reads only that explicit file and never scans a directory or fetches a URL; for a web page, use your own web tool and pass the extracted text with a locator. ' +
|
|
16
|
+
'Content is stored locally in the udt storage domain. Identical content is deduplicated by SHA-256. ' +
|
|
17
|
+
'After adding, cite passages on lesson blocks with sourceRefs; never invent a sourceId.',
|
|
18
|
+
parameters: {
|
|
19
|
+
kind: { type: 'string', required: true, enum: ['text', 'file', 'markdown'] },
|
|
20
|
+
path: { type: 'string', description: 'Absolute path for kind=file. Never a directory or URL.' },
|
|
21
|
+
text: { type: 'string', description: 'Text for kind=text/markdown.' },
|
|
22
|
+
title: { type: 'string' },
|
|
23
|
+
locator: { type: 'string', description: 'Original URL, path or human-readable location.' },
|
|
24
|
+
},
|
|
25
|
+
output: output(),
|
|
26
|
+
execute: async (args) => {
|
|
27
|
+
const input = args;
|
|
28
|
+
if (input.kind !== 'text' && input.kind !== 'markdown' && input.kind !== 'file')
|
|
29
|
+
throw new Error('source-kind-required: use text, markdown or file');
|
|
30
|
+
const draft = input.kind === 'file'
|
|
31
|
+
? await sourceDraftFromFile(input.path ?? '')
|
|
32
|
+
: sourceDraftFromText({ text: input.text ?? '', kind: input.kind, ...(input.title === undefined ? {} : { title: input.title }), ...(input.locator === undefined ? {} : { locator: input.locator }) });
|
|
33
|
+
const { source, deduped } = await addSource(state, draft);
|
|
34
|
+
return { ...metadata(source), deduped };
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
defineTool({
|
|
38
|
+
name: 'udt_source_list',
|
|
39
|
+
description: 'List learner-owned sources with metadata only. Never returns full content; use udt_source_get for a selected source.',
|
|
40
|
+
parameters: {},
|
|
41
|
+
output: output(),
|
|
42
|
+
execute: async () => {
|
|
43
|
+
const sources = state.listSources().map(metadata);
|
|
44
|
+
return { count: sources.length, bytes: state.listSources().reduce((sum, source) => sum + source.bytes, 0), sources };
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
defineTool({
|
|
48
|
+
name: 'udt_source_get',
|
|
49
|
+
description: 'Read one learner-owned source by sourceId. This returns stored text for citation; it does not fetch anything.',
|
|
50
|
+
parameters: { sourceId: { type: 'string', required: true } },
|
|
51
|
+
output: output(),
|
|
52
|
+
execute: async (args) => {
|
|
53
|
+
const source = state.readSource(args.sourceId ?? '');
|
|
54
|
+
if (source === undefined)
|
|
55
|
+
throw new Error('no-such-source: read udt_source_list');
|
|
56
|
+
return JSON.parse(JSON.stringify(source));
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=source-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-tools.js","sourceRoot":"","sources":["../src/source-tools.ts"],"names":[],"mappings":"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"}
|
package/lib/sources.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** Local source ingestion. No network access is ever made by this module. */
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { lstat, readFile } from 'node:fs/promises';
|
|
4
|
+
import { basename, extname, isAbsolute, resolve } from 'node:path';
|
|
5
|
+
import { TextDecoder } from 'node:util';
|
|
6
|
+
import { MAX_SOURCE_BYTES, MAX_SOURCE_TITLE_CHARS, MAX_SOURCES } from './source-schema.js';
|
|
7
|
+
const ALLOWED_EXTENSIONS = new Set(['.md', '.markdown', '.txt']);
|
|
8
|
+
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
9
|
+
export function sourceDraftFromText(input) {
|
|
10
|
+
const text = input.text;
|
|
11
|
+
if (text.length === 0)
|
|
12
|
+
throw new Error('source-empty: paste some text first');
|
|
13
|
+
if (Buffer.byteLength(text, 'utf8') > MAX_SOURCE_BYTES)
|
|
14
|
+
throw new Error(`source-too-large: keep one source under ${MAX_SOURCE_BYTES} bytes`);
|
|
15
|
+
const kind = input.kind ?? 'text';
|
|
16
|
+
const title = (input.title?.trim() || (kind === 'markdown' ? 'Pasted Markdown' : 'Pasted text')).slice(0, MAX_SOURCE_TITLE_CHARS);
|
|
17
|
+
return { kind, title, locator: (input.locator?.trim() || title).slice(0, 500), content: text };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read one explicitly selected local markdown/text file.
|
|
21
|
+
*
|
|
22
|
+
* This is the only place the plugin reads outside its own storage domain. It
|
|
23
|
+
* refuses directories, symlinks, unsupported extensions and oversized files;
|
|
24
|
+
* it never scans a directory or follows a URL.
|
|
25
|
+
*/
|
|
26
|
+
export async function sourceDraftFromFile(path) {
|
|
27
|
+
if (!isAbsolute(path))
|
|
28
|
+
throw new Error('source-path-must-be-absolute: pass the full path to one file');
|
|
29
|
+
const resolved = resolve(path);
|
|
30
|
+
const stats = await lstat(resolved);
|
|
31
|
+
if (stats.isSymbolicLink())
|
|
32
|
+
throw new Error('source-symlink-refused: pass the file itself');
|
|
33
|
+
if (!stats.isFile())
|
|
34
|
+
throw new Error('source-not-a-file: choose one markdown or text file');
|
|
35
|
+
const extension = extname(resolved).toLowerCase();
|
|
36
|
+
if (!ALLOWED_EXTENSIONS.has(extension))
|
|
37
|
+
throw new Error('source-unsupported-file: only .md, .markdown and .txt are accepted in this phase');
|
|
38
|
+
if (stats.size > MAX_SOURCE_BYTES)
|
|
39
|
+
throw new Error(`source-too-large: keep one source under ${MAX_SOURCE_BYTES} bytes`);
|
|
40
|
+
const buffer = await readFile(resolved);
|
|
41
|
+
if (buffer.byteLength > MAX_SOURCE_BYTES)
|
|
42
|
+
throw new Error(`source-too-large: keep one source under ${MAX_SOURCE_BYTES} bytes`);
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = decoder.decode(buffer);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new Error('source-not-utf8: convert the file to UTF-8 first');
|
|
49
|
+
}
|
|
50
|
+
if (content.includes('\u0000'))
|
|
51
|
+
throw new Error('source-binary: the selected file is not text');
|
|
52
|
+
const title = basename(resolved).slice(0, MAX_SOURCE_TITLE_CHARS);
|
|
53
|
+
return { kind: 'file', title, locator: resolved, content };
|
|
54
|
+
}
|
|
55
|
+
function sha256(content) {
|
|
56
|
+
return createHash('sha256').update(content, 'utf8').digest('hex');
|
|
57
|
+
}
|
|
58
|
+
export function sourceRecord(draft, now = new Date().toISOString()) {
|
|
59
|
+
const bytes = Buffer.byteLength(draft.content, 'utf8');
|
|
60
|
+
if (bytes > MAX_SOURCE_BYTES)
|
|
61
|
+
throw new Error(`source-too-large: keep one source under ${MAX_SOURCE_BYTES} bytes`);
|
|
62
|
+
return {
|
|
63
|
+
id: randomUUID(), kind: draft.kind, title: draft.title, locator: draft.locator,
|
|
64
|
+
sha256: sha256(draft.content), bytes, createdAt: now, status: 'ready', content: draft.content,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Add one source, deduplicating identical content by SHA-256. */
|
|
68
|
+
export async function addSource(store, draft, now) {
|
|
69
|
+
const record = sourceRecord(draft, now);
|
|
70
|
+
const existing = store.listSources().find((source) => source.sha256 === record.sha256 && source.status === 'ready');
|
|
71
|
+
if (existing !== undefined)
|
|
72
|
+
return { source: existing, deduped: true };
|
|
73
|
+
if (store.listSources().length >= MAX_SOURCES)
|
|
74
|
+
throw new Error(`too-many-sources: this learner already has ${MAX_SOURCES} sources`);
|
|
75
|
+
await store.writeSource(record);
|
|
76
|
+
return { source: record, deduped: false };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"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"}
|