learngraph 0.3.0 → 0.5.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/dist/cjs/index.js +1 -1
- package/dist/cjs/llm/adapters/gemini.js +156 -0
- package/dist/cjs/llm/adapters/gemini.js.map +1 -0
- package/dist/cjs/llm/adapters/index.js +12 -1
- package/dist/cjs/llm/adapters/index.js.map +1 -1
- package/dist/cjs/llm/adapters/mediapipe.js +290 -0
- package/dist/cjs/llm/adapters/mediapipe.js.map +1 -0
- package/dist/cjs/llm/adapters/openrouter.js +190 -0
- package/dist/cjs/llm/adapters/openrouter.js.map +1 -0
- package/dist/cjs/llm/index.js +9 -1
- package/dist/cjs/llm/index.js.map +1 -1
- package/dist/cjs/query/index.js +23 -4
- package/dist/cjs/query/index.js.map +1 -1
- package/dist/cjs/query/path.js +313 -0
- package/dist/cjs/query/path.js.map +1 -0
- package/dist/cjs/query/spaced-repetition.js +298 -0
- package/dist/cjs/query/spaced-repetition.js.map +1 -0
- package/dist/cjs/query/zpd.js +216 -0
- package/dist/cjs/query/zpd.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/llm/adapters/gemini.js +151 -0
- package/dist/esm/llm/adapters/gemini.js.map +1 -0
- package/dist/esm/llm/adapters/index.js +3 -0
- package/dist/esm/llm/adapters/index.js.map +1 -1
- package/dist/esm/llm/adapters/mediapipe.js +252 -0
- package/dist/esm/llm/adapters/mediapipe.js.map +1 -0
- package/dist/esm/llm/adapters/openrouter.js +185 -0
- package/dist/esm/llm/adapters/openrouter.js.map +1 -0
- package/dist/esm/llm/index.js +1 -1
- package/dist/esm/llm/index.js.map +1 -1
- package/dist/esm/query/index.js +11 -5
- package/dist/esm/query/index.js.map +1 -1
- package/dist/esm/query/path.js +308 -0
- package/dist/esm/query/path.js.map +1 -0
- package/dist/esm/query/spaced-repetition.js +292 -0
- package/dist/esm/query/spaced-repetition.js.map +1 -0
- package/dist/esm/query/zpd.js +211 -0
- package/dist/esm/query/zpd.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/llm/adapters/gemini.d.ts +30 -0
- package/dist/types/llm/adapters/gemini.d.ts.map +1 -0
- package/dist/types/llm/adapters/index.d.ts +3 -0
- package/dist/types/llm/adapters/index.d.ts.map +1 -1
- package/dist/types/llm/adapters/mediapipe.d.ts +113 -0
- package/dist/types/llm/adapters/mediapipe.d.ts.map +1 -0
- package/dist/types/llm/adapters/openrouter.d.ts +58 -0
- package/dist/types/llm/adapters/openrouter.d.ts.map +1 -0
- package/dist/types/llm/index.d.ts +2 -2
- package/dist/types/llm/index.d.ts.map +1 -1
- package/dist/types/query/index.d.ts +8 -0
- package/dist/types/query/index.d.ts.map +1 -1
- package/dist/types/query/path.d.ts +102 -0
- package/dist/types/query/path.d.ts.map +1 -0
- package/dist/types/query/spaced-repetition.d.ts +135 -0
- package/dist/types/query/spaced-repetition.d.ts.map +1 -0
- package/dist/types/query/zpd.d.ts +97 -0
- package/dist/types/query/zpd.d.ts.map +1 -0
- package/dist/types/types/llm.d.ts +40 -1
- package/dist/types/types/llm.d.ts.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenRouter LLM adapter
|
|
4
|
+
*
|
|
5
|
+
* OpenRouter provides access to many models through a single API:
|
|
6
|
+
* - OpenAI (GPT-4, GPT-3.5)
|
|
7
|
+
* - Anthropic (Claude)
|
|
8
|
+
* - Google (Gemini, PaLM)
|
|
9
|
+
* - Meta (Llama)
|
|
10
|
+
* - Mistral
|
|
11
|
+
* - And many more
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.OpenRouterAdapter = exports.OPENROUTER_MODELS = void 0;
|
|
17
|
+
exports.createOpenRouterAdapter = createOpenRouterAdapter;
|
|
18
|
+
const base_js_1 = require("./base.js");
|
|
19
|
+
/**
|
|
20
|
+
* Popular models available on OpenRouter
|
|
21
|
+
*/
|
|
22
|
+
exports.OPENROUTER_MODELS = {
|
|
23
|
+
// OpenAI
|
|
24
|
+
'openai/gpt-4o': 'openai/gpt-4o',
|
|
25
|
+
'openai/gpt-4-turbo': 'openai/gpt-4-turbo',
|
|
26
|
+
'openai/gpt-3.5-turbo': 'openai/gpt-3.5-turbo',
|
|
27
|
+
// Anthropic
|
|
28
|
+
'anthropic/claude-3.5-sonnet': 'anthropic/claude-3.5-sonnet',
|
|
29
|
+
'anthropic/claude-3-opus': 'anthropic/claude-3-opus',
|
|
30
|
+
'anthropic/claude-3-haiku': 'anthropic/claude-3-haiku',
|
|
31
|
+
// Google
|
|
32
|
+
'google/gemini-pro': 'google/gemini-pro',
|
|
33
|
+
'google/gemini-pro-1.5': 'google/gemini-pro-1.5',
|
|
34
|
+
// Meta
|
|
35
|
+
'meta-llama/llama-3.1-70b-instruct': 'meta-llama/llama-3.1-70b-instruct',
|
|
36
|
+
'meta-llama/llama-3.1-8b-instruct': 'meta-llama/llama-3.1-8b-instruct',
|
|
37
|
+
// Mistral
|
|
38
|
+
'mistralai/mistral-large': 'mistralai/mistral-large',
|
|
39
|
+
'mistralai/mistral-medium': 'mistralai/mistral-medium',
|
|
40
|
+
'mistralai/mixtral-8x7b-instruct': 'mistralai/mixtral-8x7b-instruct',
|
|
41
|
+
// DeepSeek
|
|
42
|
+
'deepseek/deepseek-chat': 'deepseek/deepseek-chat',
|
|
43
|
+
'deepseek/deepseek-coder': 'deepseek/deepseek-coder',
|
|
44
|
+
// Qwen
|
|
45
|
+
'qwen/qwen-2.5-72b-instruct': 'qwen/qwen-2.5-72b-instruct',
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Adapter for OpenRouter API
|
|
49
|
+
*
|
|
50
|
+
* OpenRouter provides unified access to 100+ models from various providers.
|
|
51
|
+
* See https://openrouter.ai/docs for full documentation.
|
|
52
|
+
*/
|
|
53
|
+
class OpenRouterAdapter extends base_js_1.BaseLLMAdapter {
|
|
54
|
+
baseUrl;
|
|
55
|
+
siteUrl;
|
|
56
|
+
appName;
|
|
57
|
+
constructor(config) {
|
|
58
|
+
super(config);
|
|
59
|
+
this.baseUrl = config.baseUrl ?? 'https://openrouter.ai/api/v1';
|
|
60
|
+
if (config.siteUrl) {
|
|
61
|
+
this.siteUrl = config.siteUrl;
|
|
62
|
+
}
|
|
63
|
+
if (config.appName) {
|
|
64
|
+
this.appName = config.appName;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
get provider() {
|
|
68
|
+
return 'openrouter';
|
|
69
|
+
}
|
|
70
|
+
async complete(request) {
|
|
71
|
+
if (!this.isConfigured()) {
|
|
72
|
+
throw new base_js_1.LLMError('OpenRouter adapter is not configured. Set OPENROUTER_API_KEY environment variable.', 'NOT_CONFIGURED', this.provider);
|
|
73
|
+
}
|
|
74
|
+
const openRouterRequest = this.buildRequest(request);
|
|
75
|
+
try {
|
|
76
|
+
const response = await this.executeRequest(openRouterRequest);
|
|
77
|
+
return this.parseResponse(response);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error instanceof base_js_1.LLMError) {
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
throw new base_js_1.LLMError(`OpenRouter API request failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'API_ERROR', this.provider, error instanceof Error ? error : undefined);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
buildRequest(request) {
|
|
87
|
+
const openRouterRequest = {
|
|
88
|
+
model: this.config.model,
|
|
89
|
+
messages: request.messages.map((m) => ({
|
|
90
|
+
role: m.role,
|
|
91
|
+
content: m.content,
|
|
92
|
+
})),
|
|
93
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens ?? 4096,
|
|
94
|
+
temperature: request.temperature ?? this.config.temperature ?? 0.3,
|
|
95
|
+
};
|
|
96
|
+
// Handle JSON response format
|
|
97
|
+
if (request.responseFormat === 'json') {
|
|
98
|
+
openRouterRequest.response_format = { type: 'json_object' };
|
|
99
|
+
}
|
|
100
|
+
return openRouterRequest;
|
|
101
|
+
}
|
|
102
|
+
async executeRequest(request) {
|
|
103
|
+
const headers = {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
106
|
+
};
|
|
107
|
+
// Add optional OpenRouter-specific headers for rankings
|
|
108
|
+
if (this.siteUrl) {
|
|
109
|
+
headers['HTTP-Referer'] = this.siteUrl;
|
|
110
|
+
}
|
|
111
|
+
if (this.appName) {
|
|
112
|
+
headers['X-Title'] = this.appName;
|
|
113
|
+
}
|
|
114
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers,
|
|
117
|
+
body: JSON.stringify(request),
|
|
118
|
+
signal: AbortSignal.timeout(this.config.timeout ?? 60000),
|
|
119
|
+
});
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
const errorBody = await response.text();
|
|
122
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
123
|
+
try {
|
|
124
|
+
const errorJson = JSON.parse(errorBody);
|
|
125
|
+
errorMessage = errorJson.error?.message ?? errorMessage;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
errorMessage = errorBody || errorMessage;
|
|
129
|
+
}
|
|
130
|
+
if (response.status === 429) {
|
|
131
|
+
throw new base_js_1.LLMError(`Rate limit exceeded: ${errorMessage}`, 'RATE_LIMIT', this.provider);
|
|
132
|
+
}
|
|
133
|
+
if (response.status === 402) {
|
|
134
|
+
throw new base_js_1.LLMError(`Payment required or insufficient credits: ${errorMessage}`, 'API_ERROR', this.provider);
|
|
135
|
+
}
|
|
136
|
+
throw new base_js_1.LLMError(`OpenRouter API error: ${errorMessage}`, 'API_ERROR', this.provider);
|
|
137
|
+
}
|
|
138
|
+
return response.json();
|
|
139
|
+
}
|
|
140
|
+
parseResponse(response) {
|
|
141
|
+
if (!response.choices || response.choices.length === 0) {
|
|
142
|
+
throw new base_js_1.LLMError('No choices in OpenRouter response', 'INVALID_RESPONSE', this.provider);
|
|
143
|
+
}
|
|
144
|
+
const choice = response.choices[0];
|
|
145
|
+
if (!choice) {
|
|
146
|
+
throw new base_js_1.LLMError('No choice in OpenRouter response', 'INVALID_RESPONSE', this.provider);
|
|
147
|
+
}
|
|
148
|
+
const content = choice.message.content;
|
|
149
|
+
// Try to parse JSON if present
|
|
150
|
+
let json;
|
|
151
|
+
try {
|
|
152
|
+
json = this.parseJSON(content);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// Not JSON, that's fine
|
|
156
|
+
}
|
|
157
|
+
// Map finish reasons to our standard format
|
|
158
|
+
const finishReason = choice.finish_reason === 'stop' ? 'stop' :
|
|
159
|
+
choice.finish_reason === 'length' ? 'length' :
|
|
160
|
+
choice.finish_reason === 'content_filter' ? 'content_filter' : 'stop';
|
|
161
|
+
return {
|
|
162
|
+
content,
|
|
163
|
+
json,
|
|
164
|
+
usage: {
|
|
165
|
+
promptTokens: response.usage.prompt_tokens,
|
|
166
|
+
completionTokens: response.usage.completion_tokens,
|
|
167
|
+
totalTokens: response.usage.total_tokens,
|
|
168
|
+
},
|
|
169
|
+
model: response.model,
|
|
170
|
+
finishReason,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.OpenRouterAdapter = OpenRouterAdapter;
|
|
175
|
+
/**
|
|
176
|
+
* Create an OpenRouter adapter from environment variables
|
|
177
|
+
*/
|
|
178
|
+
function createOpenRouterAdapter(model = 'anthropic/claude-3.5-sonnet', overrides) {
|
|
179
|
+
const apiKey = typeof process !== 'undefined' ? process.env.OPENROUTER_API_KEY : undefined;
|
|
180
|
+
const config = {
|
|
181
|
+
provider: 'openrouter',
|
|
182
|
+
model,
|
|
183
|
+
...overrides,
|
|
184
|
+
};
|
|
185
|
+
if (apiKey) {
|
|
186
|
+
config.apiKey = apiKey;
|
|
187
|
+
}
|
|
188
|
+
return new OpenRouterAdapter(config);
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../../src/llm/adapters/openrouter.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/llm/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @packageDocumentation
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.buildDecompositionPrompt = exports.buildBloomPrompt = exports.buildPrerequisitePrompt = exports.buildExtractionPrompt = exports.DECOMPOSITION_SCHEMA = exports.BLOOM_ANALYSIS_SCHEMA = exports.PREREQUISITE_SCHEMA = exports.EXTRACTION_SCHEMA = exports.SYSTEM_PROMPTS = exports.createOrchestrator = exports.LLMOrchestrator = exports.createOllamaAdapter = exports.OllamaAdapter = exports.createAnthropicAdapter = exports.AnthropicAdapter = exports.createOpenAIAdapter = exports.OpenAIAdapter = exports.DEFAULT_CONFIG = exports.LLMError = exports.BaseLLMAdapter = void 0;
|
|
8
|
+
exports.buildDecompositionPrompt = exports.buildBloomPrompt = exports.buildPrerequisitePrompt = exports.buildExtractionPrompt = exports.DECOMPOSITION_SCHEMA = exports.BLOOM_ANALYSIS_SCHEMA = exports.PREREQUISITE_SCHEMA = exports.EXTRACTION_SCHEMA = exports.SYSTEM_PROMPTS = exports.createOrchestrator = exports.LLMOrchestrator = exports.MEDIAPIPE_MODELS = exports.createMediaPipeAdapter = exports.MediaPipeAdapter = exports.OPENROUTER_MODELS = exports.createOpenRouterAdapter = exports.OpenRouterAdapter = exports.createGeminiAdapter = exports.GeminiAdapter = exports.createOllamaAdapter = exports.OllamaAdapter = exports.createAnthropicAdapter = exports.AnthropicAdapter = exports.createOpenAIAdapter = exports.OpenAIAdapter = exports.DEFAULT_CONFIG = exports.LLMError = exports.BaseLLMAdapter = void 0;
|
|
9
9
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
10
|
// Adapters
|
|
11
11
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -19,6 +19,14 @@ Object.defineProperty(exports, "AnthropicAdapter", { enumerable: true, get: func
|
|
|
19
19
|
Object.defineProperty(exports, "createAnthropicAdapter", { enumerable: true, get: function () { return index_js_1.createAnthropicAdapter; } });
|
|
20
20
|
Object.defineProperty(exports, "OllamaAdapter", { enumerable: true, get: function () { return index_js_1.OllamaAdapter; } });
|
|
21
21
|
Object.defineProperty(exports, "createOllamaAdapter", { enumerable: true, get: function () { return index_js_1.createOllamaAdapter; } });
|
|
22
|
+
Object.defineProperty(exports, "GeminiAdapter", { enumerable: true, get: function () { return index_js_1.GeminiAdapter; } });
|
|
23
|
+
Object.defineProperty(exports, "createGeminiAdapter", { enumerable: true, get: function () { return index_js_1.createGeminiAdapter; } });
|
|
24
|
+
Object.defineProperty(exports, "OpenRouterAdapter", { enumerable: true, get: function () { return index_js_1.OpenRouterAdapter; } });
|
|
25
|
+
Object.defineProperty(exports, "createOpenRouterAdapter", { enumerable: true, get: function () { return index_js_1.createOpenRouterAdapter; } });
|
|
26
|
+
Object.defineProperty(exports, "OPENROUTER_MODELS", { enumerable: true, get: function () { return index_js_1.OPENROUTER_MODELS; } });
|
|
27
|
+
Object.defineProperty(exports, "MediaPipeAdapter", { enumerable: true, get: function () { return index_js_1.MediaPipeAdapter; } });
|
|
28
|
+
Object.defineProperty(exports, "createMediaPipeAdapter", { enumerable: true, get: function () { return index_js_1.createMediaPipeAdapter; } });
|
|
29
|
+
Object.defineProperty(exports, "MEDIAPIPE_MODELS", { enumerable: true, get: function () { return index_js_1.MEDIAPIPE_MODELS; } });
|
|
22
30
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
31
|
// Orchestrator
|
|
24
32
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/llm/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/llm/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAgCH,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAChF,gDAkB6B;AAjB3B,0GAAA,cAAc,OAAA;AACd,oGAAA,QAAQ,OAAA;AACR,0GAAA,cAAc,OAAA;AACd,yGAAA,aAAa,OAAA;AACb,+GAAA,mBAAmB,OAAA;AACnB,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AACtB,yGAAA,aAAa,OAAA;AACb,+GAAA,mBAAmB,OAAA;AACnB,yGAAA,aAAa,OAAA;AACb,+GAAA,mBAAmB,OAAA;AACnB,6GAAA,iBAAiB,OAAA;AACjB,mHAAA,uBAAuB,OAAA;AACvB,6GAAA,iBAAiB,OAAA;AACjB,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AACtB,4GAAA,gBAAgB,OAAA;AAIlB,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAChF,qDAAwE;AAA/D,kHAAA,eAAe,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAE5C,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAChF,2CAUsB;AATpB,4GAAA,cAAc,OAAA;AACd,+GAAA,iBAAiB,OAAA;AACjB,iHAAA,mBAAmB,OAAA;AACnB,mHAAA,qBAAqB,OAAA;AACrB,kHAAA,oBAAoB,OAAA;AACpB,mHAAA,qBAAqB,OAAA;AACrB,qHAAA,uBAAuB,OAAA;AACvB,8GAAA,gBAAgB,OAAA;AAChB,sHAAA,wBAAwB,OAAA"}
|
package/dist/cjs/query/index.js
CHANGED
|
@@ -2,11 +2,30 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Query and traversal engines
|
|
4
4
|
*
|
|
5
|
+
* This module provides intelligent query engines for:
|
|
6
|
+
* - Zone of Proximal Development (ZPD) calculation
|
|
7
|
+
* - Learning path generation
|
|
8
|
+
* - Spaced repetition scheduling
|
|
9
|
+
*
|
|
5
10
|
* @packageDocumentation
|
|
6
11
|
*/
|
|
7
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
exports.SM2_CONSTANTS = exports.REVIEW_DEFAULTS = exports.calculateSM2 = exports.createSpacedRepetitionScheduler = exports.SpacedRepetitionScheduler = exports.PATH_DEFAULTS = exports.createPathGenerator = exports.PathGenerator = exports.ZPD_DEFAULTS = exports.createZPDCalculator = exports.ZPDCalculator = void 0;
|
|
14
|
+
// ZPD Calculator
|
|
15
|
+
var zpd_js_1 = require("./zpd.js");
|
|
16
|
+
Object.defineProperty(exports, "ZPDCalculator", { enumerable: true, get: function () { return zpd_js_1.ZPDCalculator; } });
|
|
17
|
+
Object.defineProperty(exports, "createZPDCalculator", { enumerable: true, get: function () { return zpd_js_1.createZPDCalculator; } });
|
|
18
|
+
Object.defineProperty(exports, "ZPD_DEFAULTS", { enumerable: true, get: function () { return zpd_js_1.ZPD_DEFAULTS; } });
|
|
19
|
+
// Learning Path Generator
|
|
20
|
+
var path_js_1 = require("./path.js");
|
|
21
|
+
Object.defineProperty(exports, "PathGenerator", { enumerable: true, get: function () { return path_js_1.PathGenerator; } });
|
|
22
|
+
Object.defineProperty(exports, "createPathGenerator", { enumerable: true, get: function () { return path_js_1.createPathGenerator; } });
|
|
23
|
+
Object.defineProperty(exports, "PATH_DEFAULTS", { enumerable: true, get: function () { return path_js_1.PATH_DEFAULTS; } });
|
|
24
|
+
// Spaced Repetition Scheduler
|
|
25
|
+
var spaced_repetition_js_1 = require("./spaced-repetition.js");
|
|
26
|
+
Object.defineProperty(exports, "SpacedRepetitionScheduler", { enumerable: true, get: function () { return spaced_repetition_js_1.SpacedRepetitionScheduler; } });
|
|
27
|
+
Object.defineProperty(exports, "createSpacedRepetitionScheduler", { enumerable: true, get: function () { return spaced_repetition_js_1.createSpacedRepetitionScheduler; } });
|
|
28
|
+
Object.defineProperty(exports, "calculateSM2", { enumerable: true, get: function () { return spaced_repetition_js_1.calculateSM2; } });
|
|
29
|
+
Object.defineProperty(exports, "REVIEW_DEFAULTS", { enumerable: true, get: function () { return spaced_repetition_js_1.REVIEW_DEFAULTS; } });
|
|
30
|
+
Object.defineProperty(exports, "SM2_CONSTANTS", { enumerable: true, get: function () { return spaced_repetition_js_1.SM2_CONSTANTS; } });
|
|
12
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/query/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/query/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAmBH,iBAAiB;AACjB,mCAKkB;AAJhB,uGAAA,aAAa,OAAA;AACb,6GAAA,mBAAmB,OAAA;AACnB,sGAAA,YAAY,OAAA;AAId,0BAA0B;AAC1B,qCAKmB;AAJjB,wGAAA,aAAa,OAAA;AACb,8GAAA,mBAAmB,OAAA;AACnB,wGAAA,aAAa,OAAA;AAIf,8BAA8B;AAC9B,+DASgC;AAR9B,iIAAA,yBAAyB,OAAA;AACzB,uIAAA,+BAA+B,OAAA;AAC/B,oHAAA,YAAY,OAAA;AACZ,uHAAA,eAAe,OAAA;AACf,qHAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Learning Path Generator
|
|
4
|
+
*
|
|
5
|
+
* Generates personalized learning paths from current state to target skills.
|
|
6
|
+
* Uses topological sorting and groups skills into manageable sessions.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.PathGenerator = exports.PATH_DEFAULTS = void 0;
|
|
12
|
+
exports.createPathGenerator = createPathGenerator;
|
|
13
|
+
/**
|
|
14
|
+
* Default options for path generation
|
|
15
|
+
*/
|
|
16
|
+
exports.PATH_DEFAULTS = {
|
|
17
|
+
sessionMinutes: 30,
|
|
18
|
+
maxPathLength: 100,
|
|
19
|
+
includeReview: false,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Learning Path Generator
|
|
23
|
+
*
|
|
24
|
+
* Generates optimal learning paths to reach target skills by:
|
|
25
|
+
* 1. Finding all unmastered prerequisites
|
|
26
|
+
* 2. Topologically sorting based on dependencies
|
|
27
|
+
* 3. Grouping into sessions based on cognitive load
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const generator = new PathGenerator(storage);
|
|
32
|
+
*
|
|
33
|
+
* const path = await generator.generatePath(
|
|
34
|
+
* 'advanced-skill',
|
|
35
|
+
* learnerState,
|
|
36
|
+
* { sessionMinutes: 45 }
|
|
37
|
+
* );
|
|
38
|
+
*
|
|
39
|
+
* console.log(`Path has ${path.skills.length} skills`);
|
|
40
|
+
* console.log(`Estimated time: ${path.totalMinutes} minutes`);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
class PathGenerator {
|
|
44
|
+
storage;
|
|
45
|
+
constructor(storage) {
|
|
46
|
+
this.storage = storage;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a learning path to a target skill
|
|
50
|
+
*
|
|
51
|
+
* @param targetId - The skill to learn
|
|
52
|
+
* @param learner - Current learner state
|
|
53
|
+
* @param options - Path generation options
|
|
54
|
+
* @returns Learning path with skills grouped into sessions
|
|
55
|
+
*/
|
|
56
|
+
async generatePath(targetId, learner, options = {}) {
|
|
57
|
+
const opts = { ...exports.PATH_DEFAULTS, ...options };
|
|
58
|
+
const target = await this.storage.getSkill(targetId);
|
|
59
|
+
if (!target) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
// Check if already mastered
|
|
63
|
+
const targetMastery = learner.masteryStates.get(targetId);
|
|
64
|
+
if (targetMastery && targetMastery.mastery >= target.masteryThreshold) {
|
|
65
|
+
// Already mastered - return empty path
|
|
66
|
+
return {
|
|
67
|
+
target,
|
|
68
|
+
skills: [],
|
|
69
|
+
totalMinutes: 0,
|
|
70
|
+
sessions: [],
|
|
71
|
+
checkpoints: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Get all prerequisites (transitive)
|
|
75
|
+
const allPrereqs = await this.getTransitivePrerequisites(targetId);
|
|
76
|
+
// Filter to unmastered skills
|
|
77
|
+
const skillsToLearn = await this.filterUnmastered([...allPrereqs, target], learner, opts.includeReview);
|
|
78
|
+
// Topologically sort
|
|
79
|
+
const sorted = await this.topologicalSort(skillsToLearn);
|
|
80
|
+
// Apply max length limit
|
|
81
|
+
const limited = opts.maxPathLength
|
|
82
|
+
? sorted.slice(0, opts.maxPathLength)
|
|
83
|
+
: sorted;
|
|
84
|
+
// Calculate total time
|
|
85
|
+
const totalMinutes = limited.reduce((sum, skill) => sum + skill.estimatedMinutes, 0);
|
|
86
|
+
// Group into sessions
|
|
87
|
+
const sessions = this.groupIntoSessions(limited, opts.sessionMinutes);
|
|
88
|
+
// Identify checkpoints (threshold concepts)
|
|
89
|
+
const checkpoints = limited.filter((skill) => skill.isThresholdConcept);
|
|
90
|
+
return {
|
|
91
|
+
target,
|
|
92
|
+
skills: limited,
|
|
93
|
+
totalMinutes,
|
|
94
|
+
sessions,
|
|
95
|
+
checkpoints,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generate paths to multiple target skills
|
|
100
|
+
*
|
|
101
|
+
* @param targetIds - Skills to learn
|
|
102
|
+
* @param learner - Current learner state
|
|
103
|
+
* @param options - Path generation options
|
|
104
|
+
* @returns Array of learning paths
|
|
105
|
+
*/
|
|
106
|
+
async generatePaths(targetIds, learner, options = {}) {
|
|
107
|
+
const paths = [];
|
|
108
|
+
for (const targetId of targetIds) {
|
|
109
|
+
const path = await this.generatePath(targetId, learner, options);
|
|
110
|
+
if (path) {
|
|
111
|
+
paths.push(path);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return paths;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get a merged learning path for multiple targets
|
|
118
|
+
* Combines all required skills and eliminates duplicates
|
|
119
|
+
*/
|
|
120
|
+
async generateMergedPath(targetIds, learner, options = {}) {
|
|
121
|
+
const opts = { ...exports.PATH_DEFAULTS, ...options };
|
|
122
|
+
// Get all target skills
|
|
123
|
+
const targets = [];
|
|
124
|
+
for (const id of targetIds) {
|
|
125
|
+
const skill = await this.storage.getSkill(id);
|
|
126
|
+
if (skill) {
|
|
127
|
+
targets.push(skill);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (targets.length === 0) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
// Collect all unmastered prerequisites from all targets
|
|
134
|
+
const allSkillsSet = new Set();
|
|
135
|
+
const allSkills = [];
|
|
136
|
+
for (const target of targets) {
|
|
137
|
+
const prereqs = await this.getTransitivePrerequisites(target.id);
|
|
138
|
+
const allForTarget = [...prereqs, target];
|
|
139
|
+
for (const skill of allForTarget) {
|
|
140
|
+
if (!allSkillsSet.has(skill.id)) {
|
|
141
|
+
allSkillsSet.add(skill.id);
|
|
142
|
+
allSkills.push(skill);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Filter to unmastered
|
|
147
|
+
const skillsToLearn = await this.filterUnmastered(allSkills, learner, opts.includeReview);
|
|
148
|
+
// Topologically sort
|
|
149
|
+
const sorted = await this.topologicalSort(skillsToLearn);
|
|
150
|
+
// Apply max length
|
|
151
|
+
const limited = opts.maxPathLength
|
|
152
|
+
? sorted.slice(0, opts.maxPathLength)
|
|
153
|
+
: sorted;
|
|
154
|
+
const totalMinutes = limited.reduce((sum, skill) => sum + skill.estimatedMinutes, 0);
|
|
155
|
+
const sessions = this.groupIntoSessions(limited, opts.sessionMinutes);
|
|
156
|
+
const checkpoints = limited.filter((skill) => skill.isThresholdConcept);
|
|
157
|
+
// Use first target as the primary target
|
|
158
|
+
return {
|
|
159
|
+
target: targets[0],
|
|
160
|
+
skills: limited,
|
|
161
|
+
totalMinutes,
|
|
162
|
+
sessions,
|
|
163
|
+
checkpoints,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get all transitive prerequisites of a skill
|
|
168
|
+
*/
|
|
169
|
+
async getTransitivePrerequisites(skillId) {
|
|
170
|
+
const visited = new Set();
|
|
171
|
+
const result = [];
|
|
172
|
+
const visit = async (id) => {
|
|
173
|
+
if (visited.has(id)) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
visited.add(id);
|
|
177
|
+
const prereqs = await this.storage.getPrerequisitesOf(id);
|
|
178
|
+
for (const prereq of prereqs) {
|
|
179
|
+
await visit(prereq.id);
|
|
180
|
+
if (!result.some((s) => s.id === prereq.id)) {
|
|
181
|
+
result.push(prereq);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
await visit(skillId);
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Filter skills to only unmastered ones
|
|
190
|
+
*/
|
|
191
|
+
async filterUnmastered(skills, learner, includeReview) {
|
|
192
|
+
return skills.filter((skill) => {
|
|
193
|
+
const mastery = learner.masteryStates.get(skill.id);
|
|
194
|
+
const level = mastery?.mastery ?? 0;
|
|
195
|
+
if (includeReview) {
|
|
196
|
+
// Include if below 100% mastery
|
|
197
|
+
return level < 1.0;
|
|
198
|
+
}
|
|
199
|
+
// Include if below mastery threshold
|
|
200
|
+
return level < skill.masteryThreshold;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Topologically sort skills based on prerequisites
|
|
205
|
+
* Skills with no unmastered prerequisites come first
|
|
206
|
+
*/
|
|
207
|
+
async topologicalSort(skills) {
|
|
208
|
+
const skillMap = new Map(skills.map((s) => [s.id, s]));
|
|
209
|
+
const result = [];
|
|
210
|
+
const visited = new Set();
|
|
211
|
+
const visiting = new Set(); // For cycle detection
|
|
212
|
+
const visit = async (skill) => {
|
|
213
|
+
if (visited.has(skill.id)) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (visiting.has(skill.id)) {
|
|
217
|
+
// Cycle detected - skip to avoid infinite loop
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
visiting.add(skill.id);
|
|
221
|
+
// Visit prerequisites first (only those in our skill set)
|
|
222
|
+
const prereqs = await this.storage.getPrerequisitesOf(skill.id);
|
|
223
|
+
for (const prereq of prereqs) {
|
|
224
|
+
const prereqSkill = skillMap.get(prereq.id);
|
|
225
|
+
if (prereqSkill && !visited.has(prereq.id)) {
|
|
226
|
+
await visit(prereqSkill);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
visiting.delete(skill.id);
|
|
230
|
+
visited.add(skill.id);
|
|
231
|
+
result.push(skill);
|
|
232
|
+
};
|
|
233
|
+
// Visit all skills
|
|
234
|
+
for (const skill of skills) {
|
|
235
|
+
if (!visited.has(skill.id)) {
|
|
236
|
+
await visit(skill);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Group skills into learning sessions based on target duration
|
|
243
|
+
*/
|
|
244
|
+
groupIntoSessions(skills, targetMinutes) {
|
|
245
|
+
const sessions = [];
|
|
246
|
+
let currentSession = [];
|
|
247
|
+
let currentDuration = 0;
|
|
248
|
+
for (const skill of skills) {
|
|
249
|
+
// Start new session if current would exceed target
|
|
250
|
+
if (currentDuration + skill.estimatedMinutes > targetMinutes &&
|
|
251
|
+
currentSession.length > 0) {
|
|
252
|
+
sessions.push(this.createSession(sessions.length + 1, currentSession));
|
|
253
|
+
currentSession = [];
|
|
254
|
+
currentDuration = 0;
|
|
255
|
+
}
|
|
256
|
+
currentSession.push(skill);
|
|
257
|
+
currentDuration += skill.estimatedMinutes;
|
|
258
|
+
}
|
|
259
|
+
// Add final session if not empty
|
|
260
|
+
if (currentSession.length > 0) {
|
|
261
|
+
sessions.push(this.createSession(sessions.length + 1, currentSession));
|
|
262
|
+
}
|
|
263
|
+
return sessions;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Create a learning session from a group of skills
|
|
267
|
+
*/
|
|
268
|
+
createSession(sessionNumber, skills) {
|
|
269
|
+
const durationMinutes = skills.reduce((sum, s) => sum + s.estimatedMinutes, 0);
|
|
270
|
+
// Determine focus from most common tag or domain
|
|
271
|
+
const focus = this.determineFocus(skills);
|
|
272
|
+
// Build session object, only include focus if defined
|
|
273
|
+
const session = {
|
|
274
|
+
sessionNumber,
|
|
275
|
+
skills,
|
|
276
|
+
durationMinutes,
|
|
277
|
+
};
|
|
278
|
+
if (focus !== undefined) {
|
|
279
|
+
session.focus = focus;
|
|
280
|
+
}
|
|
281
|
+
return session;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Determine the focus/theme of a session
|
|
285
|
+
*/
|
|
286
|
+
determineFocus(skills) {
|
|
287
|
+
// Count tag occurrences
|
|
288
|
+
const tagCounts = new Map();
|
|
289
|
+
for (const skill of skills) {
|
|
290
|
+
for (const tag of skill.tags) {
|
|
291
|
+
tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Find most common tag
|
|
295
|
+
let maxCount = 0;
|
|
296
|
+
let focus;
|
|
297
|
+
for (const [tag, count] of tagCounts) {
|
|
298
|
+
if (count > maxCount) {
|
|
299
|
+
maxCount = count;
|
|
300
|
+
focus = tag;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return focus;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
exports.PathGenerator = PathGenerator;
|
|
307
|
+
/**
|
|
308
|
+
* Create a path generator
|
|
309
|
+
*/
|
|
310
|
+
function createPathGenerator(storage) {
|
|
311
|
+
return new PathGenerator(storage);
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/query/path.ts"],"names":[],"mappings":"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"}
|