learngraph 0.2.0 → 0.3.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 +82 -1
- package/dist/cjs/llm/adapters/anthropic.js +124 -0
- package/dist/cjs/llm/adapters/anthropic.js.map +1 -0
- package/dist/cjs/llm/adapters/base.js +100 -0
- package/dist/cjs/llm/adapters/base.js.map +1 -0
- package/dist/cjs/llm/adapters/index.js +22 -0
- package/dist/cjs/llm/adapters/index.js.map +1 -0
- package/dist/cjs/llm/adapters/ollama.js +149 -0
- package/dist/cjs/llm/adapters/ollama.js.map +1 -0
- package/dist/cjs/llm/adapters/openai.js +126 -0
- package/dist/cjs/llm/adapters/openai.js.map +1 -0
- package/dist/cjs/llm/index.js +34 -5
- package/dist/cjs/llm/index.js.map +1 -1
- package/dist/cjs/llm/orchestrator.js +219 -0
- package/dist/cjs/llm/orchestrator.js.map +1 -0
- package/dist/cjs/llm/prompts.js +367 -0
- package/dist/cjs/llm/prompts.js.map +1 -0
- package/dist/cjs/types/llm.js +8 -0
- package/dist/cjs/types/llm.js.map +1 -0
- package/dist/esm/llm/adapters/anthropic.js +119 -0
- package/dist/esm/llm/adapters/anthropic.js.map +1 -0
- package/dist/esm/llm/adapters/base.js +95 -0
- package/dist/esm/llm/adapters/base.js.map +1 -0
- package/dist/esm/llm/adapters/index.js +10 -0
- package/dist/esm/llm/adapters/index.js.map +1 -0
- package/dist/esm/llm/adapters/ollama.js +144 -0
- package/dist/esm/llm/adapters/ollama.js.map +1 -0
- package/dist/esm/llm/adapters/openai.js +121 -0
- package/dist/esm/llm/adapters/openai.js.map +1 -0
- package/dist/esm/llm/index.js +12 -6
- package/dist/esm/llm/index.js.map +1 -1
- package/dist/esm/llm/orchestrator.js +214 -0
- package/dist/esm/llm/orchestrator.js.map +1 -0
- package/dist/esm/llm/prompts.js +360 -0
- package/dist/esm/llm/prompts.js.map +1 -0
- package/dist/esm/types/llm.js +7 -0
- package/dist/esm/types/llm.js.map +1 -0
- package/dist/types/llm/adapters/anthropic.d.ts +21 -0
- package/dist/types/llm/adapters/anthropic.d.ts.map +1 -0
- package/dist/types/llm/adapters/base.d.ts +46 -0
- package/dist/types/llm/adapters/base.d.ts.map +1 -0
- package/dist/types/llm/adapters/index.d.ts +11 -0
- package/dist/types/llm/adapters/index.d.ts.map +1 -0
- package/dist/types/llm/adapters/ollama.d.ts +30 -0
- package/dist/types/llm/adapters/ollama.d.ts.map +1 -0
- package/dist/types/llm/adapters/openai.d.ts +22 -0
- package/dist/types/llm/adapters/openai.d.ts.map +1 -0
- package/dist/types/llm/index.d.ts +5 -0
- package/dist/types/llm/index.d.ts.map +1 -1
- package/dist/types/llm/orchestrator.d.ts +35 -0
- package/dist/types/llm/orchestrator.d.ts.map +1 -0
- package/dist/types/llm/prompts.d.ts +269 -0
- package/dist/types/llm/prompts.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/llm.d.ts +298 -0
- package/dist/types/types/llm.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,6 +156,81 @@ await storage.connect({
|
|
|
156
156
|
});
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
+
## LLM-Powered Curriculum Decomposition
|
|
160
|
+
|
|
161
|
+
LearnGraph can automatically decompose curriculum content into skill graphs using LLMs:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { createOpenAIAdapter, createOrchestrator } from 'learngraph/llm';
|
|
165
|
+
|
|
166
|
+
// Create an adapter (OpenAI, Anthropic, or Ollama)
|
|
167
|
+
const adapter = createOpenAIAdapter('gpt-4o');
|
|
168
|
+
const orchestrator = createOrchestrator(adapter);
|
|
169
|
+
|
|
170
|
+
// Extract skills from curriculum content
|
|
171
|
+
const extraction = await orchestrator.extractSkills({
|
|
172
|
+
content: `
|
|
173
|
+
Chapter 1: Introduction to Calculus
|
|
174
|
+
- Understand the concept of limits
|
|
175
|
+
- Calculate derivatives using the power rule
|
|
176
|
+
- Apply differentiation to real-world problems
|
|
177
|
+
`,
|
|
178
|
+
domain: 'Mathematics',
|
|
179
|
+
gradeLevel: 'College',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
console.log(extraction.skills);
|
|
183
|
+
// [{ name: 'Limits', bloomLevel: 'understand', ... }, ...]
|
|
184
|
+
|
|
185
|
+
// Infer prerequisites between skills
|
|
186
|
+
const prerequisites = await orchestrator.inferPrerequisites({
|
|
187
|
+
skills: extraction.skills,
|
|
188
|
+
domain: 'Mathematics',
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Full decomposition: skills + prerequisites in one call
|
|
192
|
+
const decomposition = await orchestrator.decompose({
|
|
193
|
+
content: 'Full calculus syllabus here...',
|
|
194
|
+
title: 'Calculus I',
|
|
195
|
+
domain: 'Mathematics',
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Returns: { title, skills, prerequisites, skillInputs }
|
|
199
|
+
// skillInputs are ready to insert into storage
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Supported LLM Providers
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import {
|
|
206
|
+
createOpenAIAdapter, // GPT-4o, GPT-4, GPT-3.5
|
|
207
|
+
createAnthropicAdapter, // Claude 3.5, Claude 3
|
|
208
|
+
createOllamaAdapter, // Llama, Mistral, etc.
|
|
209
|
+
} from 'learngraph/llm';
|
|
210
|
+
|
|
211
|
+
// OpenAI (set OPENAI_API_KEY env var)
|
|
212
|
+
const openai = createOpenAIAdapter('gpt-4o');
|
|
213
|
+
|
|
214
|
+
// Anthropic (set ANTHROPIC_API_KEY env var)
|
|
215
|
+
const anthropic = createAnthropicAdapter('claude-3-5-sonnet-20241022');
|
|
216
|
+
|
|
217
|
+
// Ollama (local models, no API key needed)
|
|
218
|
+
const ollama = createOllamaAdapter('llama3.2');
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Bloom's Taxonomy Analysis
|
|
222
|
+
|
|
223
|
+
Analyze the cognitive level of learning objectives:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const analysis = await orchestrator.analyzeBloomLevel({
|
|
227
|
+
text: 'Compare and contrast mitosis and meiosis',
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
console.log(analysis);
|
|
231
|
+
// { level: 'analyze', confidence: 0.9, indicators: ['compare', 'contrast'] }
|
|
232
|
+
```
|
|
233
|
+
|
|
159
234
|
## Submodule Exports
|
|
160
235
|
|
|
161
236
|
```typescript
|
|
@@ -166,7 +241,13 @@ import { SkillNode, SkillEdge } from 'learngraph';
|
|
|
166
241
|
import { MemoryStorage, LevelGraphStorage, Neo4jStorage } from 'learngraph/storage';
|
|
167
242
|
|
|
168
243
|
// LLM integration for curriculum decomposition
|
|
169
|
-
import {
|
|
244
|
+
import {
|
|
245
|
+
createOpenAIAdapter,
|
|
246
|
+
createAnthropicAdapter,
|
|
247
|
+
createOllamaAdapter,
|
|
248
|
+
createOrchestrator,
|
|
249
|
+
LLMOrchestrator,
|
|
250
|
+
} from 'learngraph/llm';
|
|
170
251
|
|
|
171
252
|
// Query builders and ZPD calculation
|
|
172
253
|
import { ZPDResult, LearningPath } from 'learngraph/query';
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic adapter for LLM integration
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.AnthropicAdapter = void 0;
|
|
9
|
+
exports.createAnthropicAdapter = createAnthropicAdapter;
|
|
10
|
+
const base_js_1 = require("./base.js");
|
|
11
|
+
/**
|
|
12
|
+
* Anthropic adapter for Claude models
|
|
13
|
+
*/
|
|
14
|
+
class AnthropicAdapter extends base_js_1.BaseLLMAdapter {
|
|
15
|
+
baseUrl;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super(config);
|
|
18
|
+
this.baseUrl = config.baseUrl ?? 'https://api.anthropic.com/v1';
|
|
19
|
+
}
|
|
20
|
+
get provider() {
|
|
21
|
+
return 'anthropic';
|
|
22
|
+
}
|
|
23
|
+
async complete(request) {
|
|
24
|
+
if (!this.isConfigured()) {
|
|
25
|
+
throw new base_js_1.LLMError('Anthropic adapter not configured. Set ANTHROPIC_API_KEY or pass apiKey in config.', 'NOT_CONFIGURED', this.provider);
|
|
26
|
+
}
|
|
27
|
+
return this.withRetry(async () => {
|
|
28
|
+
// Extract system message
|
|
29
|
+
const systemMessage = request.messages.find((m) => m.role === 'system');
|
|
30
|
+
const otherMessages = request.messages.filter((m) => m.role !== 'system');
|
|
31
|
+
const headers = {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'x-api-key': this.config.apiKey,
|
|
34
|
+
'anthropic-version': '2023-06-01',
|
|
35
|
+
};
|
|
36
|
+
const body = {
|
|
37
|
+
model: this.config.model,
|
|
38
|
+
messages: otherMessages.map((m) => ({
|
|
39
|
+
role: m.role,
|
|
40
|
+
content: m.content,
|
|
41
|
+
})),
|
|
42
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens ?? base_js_1.DEFAULT_CONFIG.maxTokens,
|
|
43
|
+
};
|
|
44
|
+
// Add system message if present
|
|
45
|
+
if (systemMessage) {
|
|
46
|
+
body.system = systemMessage.content;
|
|
47
|
+
}
|
|
48
|
+
// Temperature (Anthropic uses 0-1 scale like OpenAI)
|
|
49
|
+
const temp = request.temperature ?? this.config.temperature ?? base_js_1.DEFAULT_CONFIG.temperature;
|
|
50
|
+
if (temp !== undefined) {
|
|
51
|
+
body.temperature = temp;
|
|
52
|
+
}
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeout = setTimeout(() => controller.abort(), this.config.timeout ?? base_js_1.DEFAULT_CONFIG.timeout);
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(`${this.baseUrl}/messages`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers,
|
|
59
|
+
body: JSON.stringify(body),
|
|
60
|
+
signal: controller.signal,
|
|
61
|
+
});
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
65
|
+
const errorMessage = errorData.error?.message ?? `HTTP ${response.status}`;
|
|
66
|
+
if (response.status === 429) {
|
|
67
|
+
throw new base_js_1.LLMError(`Rate limit exceeded: ${errorMessage}`, 'RATE_LIMIT', this.provider);
|
|
68
|
+
}
|
|
69
|
+
throw new base_js_1.LLMError(`Anthropic API error: ${errorMessage}`, 'API_ERROR', this.provider);
|
|
70
|
+
}
|
|
71
|
+
const data = (await response.json());
|
|
72
|
+
// Get text content
|
|
73
|
+
const textBlock = data.content.find((block) => block.type === 'text');
|
|
74
|
+
const content = textBlock?.text ?? '';
|
|
75
|
+
let json;
|
|
76
|
+
if (request.responseFormat === 'json') {
|
|
77
|
+
json = this.parseJSON(content);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
content,
|
|
81
|
+
json,
|
|
82
|
+
usage: {
|
|
83
|
+
promptTokens: data.usage.input_tokens,
|
|
84
|
+
completionTokens: data.usage.output_tokens,
|
|
85
|
+
totalTokens: data.usage.input_tokens + data.usage.output_tokens,
|
|
86
|
+
},
|
|
87
|
+
model: data.model,
|
|
88
|
+
finishReason: data.stop_reason === 'end_turn' ? 'stop' :
|
|
89
|
+
data.stop_reason === 'max_tokens' ? 'length' : 'error',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
if (error instanceof base_js_1.LLMError) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
if (error instanceof Error) {
|
|
98
|
+
if (error.name === 'AbortError') {
|
|
99
|
+
throw new base_js_1.LLMError('Request timeout', 'TIMEOUT', this.provider, error);
|
|
100
|
+
}
|
|
101
|
+
throw new base_js_1.LLMError(`Network error: ${error.message}`, 'NETWORK_ERROR', this.provider, error);
|
|
102
|
+
}
|
|
103
|
+
throw new base_js_1.LLMError('Unknown error', 'API_ERROR', this.provider);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.AnthropicAdapter = AnthropicAdapter;
|
|
109
|
+
/**
|
|
110
|
+
* Create an Anthropic adapter from environment variables
|
|
111
|
+
*/
|
|
112
|
+
function createAnthropicAdapter(model = 'claude-3-5-sonnet-20241022', overrides) {
|
|
113
|
+
const apiKey = typeof process !== 'undefined' ? process.env.ANTHROPIC_API_KEY : undefined;
|
|
114
|
+
const config = {
|
|
115
|
+
provider: 'anthropic',
|
|
116
|
+
model,
|
|
117
|
+
...overrides,
|
|
118
|
+
};
|
|
119
|
+
if (apiKey) {
|
|
120
|
+
config.apiKey = apiKey;
|
|
121
|
+
}
|
|
122
|
+
return new AnthropicAdapter(config);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../src/llm/adapters/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base adapter class for LLM providers
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.BaseLLMAdapter = exports.DEFAULT_CONFIG = exports.LLMError = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* LLM-related errors
|
|
11
|
+
*/
|
|
12
|
+
class LLMError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
provider;
|
|
15
|
+
cause;
|
|
16
|
+
constructor(message, code, provider, cause) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.provider = provider;
|
|
20
|
+
this.cause = cause;
|
|
21
|
+
this.name = 'LLMError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.LLMError = LLMError;
|
|
25
|
+
/**
|
|
26
|
+
* Default configuration values
|
|
27
|
+
*/
|
|
28
|
+
exports.DEFAULT_CONFIG = {
|
|
29
|
+
maxTokens: 4096,
|
|
30
|
+
temperature: 0.3,
|
|
31
|
+
timeout: 60000,
|
|
32
|
+
retries: 2,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Abstract base class for LLM adapters
|
|
36
|
+
*/
|
|
37
|
+
class BaseLLMAdapter {
|
|
38
|
+
config;
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.config = {
|
|
41
|
+
...exports.DEFAULT_CONFIG,
|
|
42
|
+
...config,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
get model() {
|
|
46
|
+
return this.config.model;
|
|
47
|
+
}
|
|
48
|
+
isConfigured() {
|
|
49
|
+
if (this.provider === 'ollama') {
|
|
50
|
+
return !!this.config.model;
|
|
51
|
+
}
|
|
52
|
+
return !!this.config.apiKey && !!this.config.model;
|
|
53
|
+
}
|
|
54
|
+
getConfig() {
|
|
55
|
+
const { apiKey: _, ...rest } = this.config;
|
|
56
|
+
return rest;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Retry a function with exponential backoff
|
|
60
|
+
*/
|
|
61
|
+
async withRetry(fn, maxRetries = this.config.retries ?? exports.DEFAULT_CONFIG.retries) {
|
|
62
|
+
let lastError;
|
|
63
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
64
|
+
try {
|
|
65
|
+
return await fn();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
69
|
+
// Don't retry on certain errors
|
|
70
|
+
if (error instanceof LLMError) {
|
|
71
|
+
if (error.code === 'NOT_CONFIGURED' || error.code === 'INVALID_RESPONSE') {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (attempt < maxRetries) {
|
|
76
|
+
// Exponential backoff: 1s, 2s, 4s, ...
|
|
77
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw lastError;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse JSON from LLM response, handling common issues
|
|
86
|
+
*/
|
|
87
|
+
parseJSON(content) {
|
|
88
|
+
// Try to extract JSON from markdown code blocks
|
|
89
|
+
const jsonMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
90
|
+
const jsonStr = jsonMatch && jsonMatch[1] ? jsonMatch[1].trim() : content.trim();
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(jsonStr);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new LLMError(`Failed to parse JSON response: ${error instanceof Error ? error.message : 'Unknown error'}`, 'PARSE_ERROR', this.provider, error instanceof Error ? error : undefined);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.BaseLLMAdapter = BaseLLMAdapter;
|
|
100
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/llm/adapters/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LLM adapter exports
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.createOllamaAdapter = exports.OllamaAdapter = exports.createAnthropicAdapter = exports.AnthropicAdapter = exports.createOpenAIAdapter = exports.OpenAIAdapter = exports.DEFAULT_CONFIG = exports.LLMError = exports.BaseLLMAdapter = void 0;
|
|
9
|
+
var base_js_1 = require("./base.js");
|
|
10
|
+
Object.defineProperty(exports, "BaseLLMAdapter", { enumerable: true, get: function () { return base_js_1.BaseLLMAdapter; } });
|
|
11
|
+
Object.defineProperty(exports, "LLMError", { enumerable: true, get: function () { return base_js_1.LLMError; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return base_js_1.DEFAULT_CONFIG; } });
|
|
13
|
+
var openai_js_1 = require("./openai.js");
|
|
14
|
+
Object.defineProperty(exports, "OpenAIAdapter", { enumerable: true, get: function () { return openai_js_1.OpenAIAdapter; } });
|
|
15
|
+
Object.defineProperty(exports, "createOpenAIAdapter", { enumerable: true, get: function () { return openai_js_1.createOpenAIAdapter; } });
|
|
16
|
+
var anthropic_js_1 = require("./anthropic.js");
|
|
17
|
+
Object.defineProperty(exports, "AnthropicAdapter", { enumerable: true, get: function () { return anthropic_js_1.AnthropicAdapter; } });
|
|
18
|
+
Object.defineProperty(exports, "createAnthropicAdapter", { enumerable: true, get: function () { return anthropic_js_1.createAnthropicAdapter; } });
|
|
19
|
+
var ollama_js_1 = require("./ollama.js");
|
|
20
|
+
Object.defineProperty(exports, "OllamaAdapter", { enumerable: true, get: function () { return ollama_js_1.OllamaAdapter; } });
|
|
21
|
+
Object.defineProperty(exports, "createOllamaAdapter", { enumerable: true, get: function () { return ollama_js_1.createOllamaAdapter; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/llm/adapters/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,qCAAqE;AAA5D,yGAAA,cAAc,OAAA;AAAE,mGAAA,QAAQ,OAAA;AAAE,yGAAA,cAAc,OAAA;AAGjD,yCAAiE;AAAxD,0GAAA,aAAa,OAAA;AAAE,gHAAA,mBAAmB,OAAA;AAC3C,+CAA0E;AAAjE,gHAAA,gBAAgB,OAAA;AAAE,sHAAA,sBAAsB,OAAA;AACjD,yCAAiE;AAAxD,0GAAA,aAAa,OAAA;AAAE,gHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Ollama adapter for local LLM integration
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.OllamaAdapter = void 0;
|
|
9
|
+
exports.createOllamaAdapter = createOllamaAdapter;
|
|
10
|
+
const base_js_1 = require("./base.js");
|
|
11
|
+
/**
|
|
12
|
+
* Ollama adapter for local models
|
|
13
|
+
*/
|
|
14
|
+
class OllamaAdapter extends base_js_1.BaseLLMAdapter {
|
|
15
|
+
baseUrl;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super(config);
|
|
18
|
+
this.baseUrl = config.baseUrl ?? 'http://localhost:11434';
|
|
19
|
+
}
|
|
20
|
+
get provider() {
|
|
21
|
+
return 'ollama';
|
|
22
|
+
}
|
|
23
|
+
isConfigured() {
|
|
24
|
+
return !!this.config.model;
|
|
25
|
+
}
|
|
26
|
+
async complete(request) {
|
|
27
|
+
if (!this.isConfigured()) {
|
|
28
|
+
throw new base_js_1.LLMError('Ollama adapter not configured. Set model in config.', 'NOT_CONFIGURED', this.provider);
|
|
29
|
+
}
|
|
30
|
+
return this.withRetry(async () => {
|
|
31
|
+
const body = {
|
|
32
|
+
model: this.config.model,
|
|
33
|
+
messages: request.messages.map((m) => ({
|
|
34
|
+
role: m.role,
|
|
35
|
+
content: m.content,
|
|
36
|
+
})),
|
|
37
|
+
stream: false,
|
|
38
|
+
options: {
|
|
39
|
+
num_predict: request.maxTokens ?? this.config.maxTokens ?? base_js_1.DEFAULT_CONFIG.maxTokens,
|
|
40
|
+
temperature: request.temperature ?? this.config.temperature ?? base_js_1.DEFAULT_CONFIG.temperature,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
// Add JSON format if requested
|
|
44
|
+
if (request.responseFormat === 'json') {
|
|
45
|
+
body.format = 'json';
|
|
46
|
+
}
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
// Ollama can be slow, use longer timeout
|
|
49
|
+
const timeout = setTimeout(() => controller.abort(), this.config.timeout ?? base_js_1.DEFAULT_CONFIG.timeout * 2);
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(body),
|
|
57
|
+
signal: controller.signal,
|
|
58
|
+
});
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const errorText = await response.text().catch(() => '');
|
|
62
|
+
throw new base_js_1.LLMError(`Ollama API error: HTTP ${response.status} - ${errorText}`, 'API_ERROR', this.provider);
|
|
63
|
+
}
|
|
64
|
+
const data = (await response.json());
|
|
65
|
+
const content = data.message?.content ?? '';
|
|
66
|
+
let json;
|
|
67
|
+
if (request.responseFormat === 'json') {
|
|
68
|
+
json = this.parseJSON(content);
|
|
69
|
+
}
|
|
70
|
+
// Estimate tokens (Ollama provides eval_count)
|
|
71
|
+
const promptTokens = data.prompt_eval_count ?? Math.ceil(request.messages.reduce((acc, m) => acc + m.content.length, 0) / 4);
|
|
72
|
+
const completionTokens = data.eval_count ?? Math.ceil(content.length / 4);
|
|
73
|
+
return {
|
|
74
|
+
content,
|
|
75
|
+
json,
|
|
76
|
+
usage: {
|
|
77
|
+
promptTokens,
|
|
78
|
+
completionTokens,
|
|
79
|
+
totalTokens: promptTokens + completionTokens,
|
|
80
|
+
},
|
|
81
|
+
model: data.model,
|
|
82
|
+
finishReason: data.done ? 'stop' : 'error',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
clearTimeout(timeout);
|
|
87
|
+
if (error instanceof base_js_1.LLMError) {
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
if (error instanceof Error) {
|
|
91
|
+
if (error.name === 'AbortError') {
|
|
92
|
+
throw new base_js_1.LLMError('Request timeout', 'TIMEOUT', this.provider, error);
|
|
93
|
+
}
|
|
94
|
+
// Check for connection refused
|
|
95
|
+
if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {
|
|
96
|
+
throw new base_js_1.LLMError(`Cannot connect to Ollama at ${this.baseUrl}. Is Ollama running?`, 'NETWORK_ERROR', this.provider, error);
|
|
97
|
+
}
|
|
98
|
+
throw new base_js_1.LLMError(`Network error: ${error.message}`, 'NETWORK_ERROR', this.provider, error);
|
|
99
|
+
}
|
|
100
|
+
throw new base_js_1.LLMError('Unknown error', 'API_ERROR', this.provider);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if Ollama is available
|
|
106
|
+
*/
|
|
107
|
+
async isAvailable() {
|
|
108
|
+
try {
|
|
109
|
+
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
});
|
|
112
|
+
return response.ok;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* List available models
|
|
120
|
+
*/
|
|
121
|
+
async listModels() {
|
|
122
|
+
try {
|
|
123
|
+
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
124
|
+
method: 'GET',
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
const data = (await response.json());
|
|
130
|
+
return data.models?.map((m) => m.name) ?? [];
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.OllamaAdapter = OllamaAdapter;
|
|
138
|
+
/**
|
|
139
|
+
* Create an Ollama adapter
|
|
140
|
+
*/
|
|
141
|
+
function createOllamaAdapter(model = 'llama3.2', overrides) {
|
|
142
|
+
return new OllamaAdapter({
|
|
143
|
+
provider: 'ollama',
|
|
144
|
+
model,
|
|
145
|
+
baseUrl: 'http://localhost:11434',
|
|
146
|
+
...overrides,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../../../src/llm/adapters/ollama.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI adapter for LLM integration
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.OpenAIAdapter = void 0;
|
|
9
|
+
exports.createOpenAIAdapter = createOpenAIAdapter;
|
|
10
|
+
const base_js_1 = require("./base.js");
|
|
11
|
+
/**
|
|
12
|
+
* OpenAI adapter for chat completions
|
|
13
|
+
*/
|
|
14
|
+
class OpenAIAdapter extends base_js_1.BaseLLMAdapter {
|
|
15
|
+
baseUrl;
|
|
16
|
+
organization;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super(config);
|
|
19
|
+
this.baseUrl = config.baseUrl ?? 'https://api.openai.com/v1';
|
|
20
|
+
if (config.organization) {
|
|
21
|
+
this.organization = config.organization;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get provider() {
|
|
25
|
+
return 'openai';
|
|
26
|
+
}
|
|
27
|
+
async complete(request) {
|
|
28
|
+
if (!this.isConfigured()) {
|
|
29
|
+
throw new base_js_1.LLMError('OpenAI adapter not configured. Set OPENAI_API_KEY or pass apiKey in config.', 'NOT_CONFIGURED', this.provider);
|
|
30
|
+
}
|
|
31
|
+
return this.withRetry(async () => {
|
|
32
|
+
const headers = {
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
35
|
+
};
|
|
36
|
+
if (this.organization) {
|
|
37
|
+
headers['OpenAI-Organization'] = this.organization;
|
|
38
|
+
}
|
|
39
|
+
const body = {
|
|
40
|
+
model: this.config.model,
|
|
41
|
+
messages: request.messages.map((m) => ({
|
|
42
|
+
role: m.role,
|
|
43
|
+
content: m.content,
|
|
44
|
+
})),
|
|
45
|
+
max_tokens: request.maxTokens ?? this.config.maxTokens ?? base_js_1.DEFAULT_CONFIG.maxTokens,
|
|
46
|
+
temperature: request.temperature ?? this.config.temperature ?? base_js_1.DEFAULT_CONFIG.temperature,
|
|
47
|
+
};
|
|
48
|
+
// Add JSON mode if requested
|
|
49
|
+
if (request.responseFormat === 'json') {
|
|
50
|
+
body.response_format = { type: 'json_object' };
|
|
51
|
+
}
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeout = setTimeout(() => controller.abort(), this.config.timeout ?? base_js_1.DEFAULT_CONFIG.timeout);
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers,
|
|
58
|
+
body: JSON.stringify(body),
|
|
59
|
+
signal: controller.signal,
|
|
60
|
+
});
|
|
61
|
+
clearTimeout(timeout);
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
64
|
+
const errorMessage = errorData.error?.message ?? `HTTP ${response.status}`;
|
|
65
|
+
if (response.status === 429) {
|
|
66
|
+
throw new base_js_1.LLMError(`Rate limit exceeded: ${errorMessage}`, 'RATE_LIMIT', this.provider);
|
|
67
|
+
}
|
|
68
|
+
throw new base_js_1.LLMError(`OpenAI API error: ${errorMessage}`, 'API_ERROR', this.provider);
|
|
69
|
+
}
|
|
70
|
+
const data = (await response.json());
|
|
71
|
+
const choice = data.choices[0];
|
|
72
|
+
if (!choice) {
|
|
73
|
+
throw new base_js_1.LLMError('No response from OpenAI', 'INVALID_RESPONSE', this.provider);
|
|
74
|
+
}
|
|
75
|
+
const content = choice.message.content;
|
|
76
|
+
let json;
|
|
77
|
+
if (request.responseFormat === 'json') {
|
|
78
|
+
json = this.parseJSON(content);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
content,
|
|
82
|
+
json,
|
|
83
|
+
usage: {
|
|
84
|
+
promptTokens: data.usage.prompt_tokens,
|
|
85
|
+
completionTokens: data.usage.completion_tokens,
|
|
86
|
+
totalTokens: data.usage.total_tokens,
|
|
87
|
+
},
|
|
88
|
+
model: data.model,
|
|
89
|
+
finishReason: choice.finish_reason === 'stop' ? 'stop' :
|
|
90
|
+
choice.finish_reason === 'length' ? 'length' :
|
|
91
|
+
choice.finish_reason === 'content_filter' ? 'content_filter' : 'error',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
clearTimeout(timeout);
|
|
96
|
+
if (error instanceof base_js_1.LLMError) {
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
if (error instanceof Error) {
|
|
100
|
+
if (error.name === 'AbortError') {
|
|
101
|
+
throw new base_js_1.LLMError('Request timeout', 'TIMEOUT', this.provider, error);
|
|
102
|
+
}
|
|
103
|
+
throw new base_js_1.LLMError(`Network error: ${error.message}`, 'NETWORK_ERROR', this.provider, error);
|
|
104
|
+
}
|
|
105
|
+
throw new base_js_1.LLMError('Unknown error', 'API_ERROR', this.provider);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.OpenAIAdapter = OpenAIAdapter;
|
|
111
|
+
/**
|
|
112
|
+
* Create an OpenAI adapter from environment variables
|
|
113
|
+
*/
|
|
114
|
+
function createOpenAIAdapter(model = 'gpt-4o', overrides) {
|
|
115
|
+
const apiKey = typeof process !== 'undefined' ? process.env.OPENAI_API_KEY : undefined;
|
|
116
|
+
const config = {
|
|
117
|
+
provider: 'openai',
|
|
118
|
+
model,
|
|
119
|
+
...overrides,
|
|
120
|
+
};
|
|
121
|
+
if (apiKey) {
|
|
122
|
+
config.apiKey = apiKey;
|
|
123
|
+
}
|
|
124
|
+
return new OpenAIAdapter(config);
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../../src/llm/adapters/openai.ts"],"names":[],"mappings":"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"}
|