lazlo-ai 1.0.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/.env.example +9 -0
- package/README.md +278 -0
- package/dist/cache/semantic.d.ts +39 -0
- package/dist/cache/semantic.d.ts.map +1 -0
- package/dist/cache/semantic.js +134 -0
- package/dist/cache/semantic.js.map +1 -0
- package/dist/chains/llmchain.d.ts +65 -0
- package/dist/chains/llmchain.d.ts.map +1 -0
- package/dist/chains/llmchain.js +137 -0
- package/dist/chains/llmchain.js.map +1 -0
- package/dist/chains/rag.d.ts +23 -0
- package/dist/chains/rag.d.ts.map +1 -0
- package/dist/chains/rag.js +47 -0
- package/dist/chains/rag.js.map +1 -0
- package/dist/core/types.d.ts +130 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -0
- package/dist/document_loaders/index.d.ts +61 -0
- package/dist/document_loaders/index.d.ts.map +1 -0
- package/dist/document_loaders/index.js +183 -0
- package/dist/document_loaders/index.js.map +1 -0
- package/dist/embeddings/google.d.ts +43 -0
- package/dist/embeddings/google.d.ts.map +1 -0
- package/dist/embeddings/google.js +90 -0
- package/dist/embeddings/google.js.map +1 -0
- package/dist/embeddings/local.d.ts +64 -0
- package/dist/embeddings/local.d.ts.map +1 -0
- package/dist/embeddings/local.js +95 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/evals/judge.d.ts +22 -0
- package/dist/evals/judge.d.ts.map +1 -0
- package/dist/evals/judge.js +77 -0
- package/dist/evals/judge.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/buffer.d.ts +64 -0
- package/dist/memory/buffer.d.ts.map +1 -0
- package/dist/memory/buffer.js +168 -0
- package/dist/memory/buffer.js.map +1 -0
- package/dist/parsers/output.d.ts +64 -0
- package/dist/parsers/output.d.ts.map +1 -0
- package/dist/parsers/output.js +148 -0
- package/dist/parsers/output.js.map +1 -0
- package/dist/prompts/registry.d.ts +65 -0
- package/dist/prompts/registry.d.ts.map +1 -0
- package/dist/prompts/registry.js +170 -0
- package/dist/prompts/registry.js.map +1 -0
- package/dist/providers/ollama.d.ts +30 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +104 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai.d.ts +46 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +228 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/retrievers/index.d.ts +71 -0
- package/dist/retrievers/index.d.ts.map +1 -0
- package/dist/retrievers/index.js +130 -0
- package/dist/retrievers/index.js.map +1 -0
- package/dist/router/smartrouter.d.ts +36 -0
- package/dist/router/smartrouter.d.ts.map +1 -0
- package/dist/router/smartrouter.js +132 -0
- package/dist/router/smartrouter.js.map +1 -0
- package/dist/text_splitters/index.d.ts +28 -0
- package/dist/text_splitters/index.d.ts.map +1 -0
- package/dist/text_splitters/index.js +109 -0
- package/dist/text_splitters/index.js.map +1 -0
- package/dist/tools/decorator.d.ts +26 -0
- package/dist/tools/decorator.d.ts.map +1 -0
- package/dist/tools/decorator.js +102 -0
- package/dist/tools/decorator.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/keiro.d.ts +20 -0
- package/dist/tools/keiro.d.ts.map +1 -0
- package/dist/tools/keiro.js +67 -0
- package/dist/tools/keiro.js.map +1 -0
- package/dist/tracing/tracer.d.ts +56 -0
- package/dist/tracing/tracer.d.ts.map +1 -0
- package/dist/tracing/tracer.js +125 -0
- package/dist/tracing/tracer.js.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +50 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/pricing.d.ts +31 -0
- package/dist/utils/pricing.d.ts.map +1 -0
- package/dist/utils/pricing.js +108 -0
- package/dist/utils/pricing.js.map +1 -0
- package/dist/vectorstores/index.d.ts +62 -0
- package/dist/vectorstores/index.d.ts.map +1 -0
- package/dist/vectorstores/index.js +244 -0
- package/dist/vectorstores/index.js.map +1 -0
- package/package.json +48 -0
- package/src/cache/semantic.ts +175 -0
- package/src/chains/llmchain.ts +194 -0
- package/src/chains/rag.ts +65 -0
- package/src/core/types.ts +178 -0
- package/src/document_loaders/index.ts +223 -0
- package/src/embeddings/google.ts +119 -0
- package/src/embeddings/local.ts +118 -0
- package/src/evals/judge.ts +99 -0
- package/src/index.ts +121 -0
- package/src/memory/buffer.ts +222 -0
- package/src/parsers/output.ts +195 -0
- package/src/prompts/registry.ts +205 -0
- package/src/providers/ollama.ts +151 -0
- package/src/providers/openai.ts +320 -0
- package/src/retrievers/index.ts +182 -0
- package/src/router/smartrouter.ts +172 -0
- package/src/text_splitters/index.ts +145 -0
- package/src/tools/decorator.ts +145 -0
- package/src/tools/index.ts +7 -0
- package/src/tools/keiro.ts +92 -0
- package/src/tracing/tracer.ts +178 -0
- package/src/utils/logger.ts +62 -0
- package/src/utils/pricing.ts +133 -0
- package/src/vectorstores/index.ts +338 -0
- package/test-full.mjs +552 -0
- package/test.mjs +74 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Loaders
|
|
3
|
+
*
|
|
4
|
+
* Load documents from various sources: PDF, text, CSV, JSON, HTML
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFile } from 'fs/promises';
|
|
8
|
+
import { readFileSync } from 'fs';
|
|
9
|
+
import { join, extname } from 'path';
|
|
10
|
+
|
|
11
|
+
export interface Document {
|
|
12
|
+
pageContent: string;
|
|
13
|
+
metadata: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BaseLoader {
|
|
17
|
+
load(): Promise<Document[]>;
|
|
18
|
+
loadSync(): Document[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Text File Loader
|
|
23
|
+
*/
|
|
24
|
+
export class TextLoader implements BaseLoader {
|
|
25
|
+
constructor(private filePath: string) {}
|
|
26
|
+
|
|
27
|
+
async load(): Promise<Document[]> {
|
|
28
|
+
const content = await readFile(this.filePath, 'utf-8');
|
|
29
|
+
return this.parseContent(content);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
loadSync(): Document[] {
|
|
33
|
+
const content = readFileSync(this.filePath, 'utf-8');
|
|
34
|
+
return this.parseContent(content);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private parseContent(content: string): Document[] {
|
|
38
|
+
return [{
|
|
39
|
+
pageContent: content,
|
|
40
|
+
metadata: {
|
|
41
|
+
source: this.filePath,
|
|
42
|
+
type: 'text',
|
|
43
|
+
},
|
|
44
|
+
}];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* CSV File Loader
|
|
50
|
+
*/
|
|
51
|
+
export class CSVLoader implements BaseLoader {
|
|
52
|
+
constructor(
|
|
53
|
+
private filePath: string,
|
|
54
|
+
private options: {
|
|
55
|
+
delimiter?: string;
|
|
56
|
+
headers?: string[];
|
|
57
|
+
skipEmptyLines?: boolean;
|
|
58
|
+
} = {}
|
|
59
|
+
) {}
|
|
60
|
+
|
|
61
|
+
async load(): Promise<Document[]> {
|
|
62
|
+
const content = await readFile(this.filePath, 'utf-8');
|
|
63
|
+
return this.parseCSV(content);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
loadSync(): Document[] {
|
|
67
|
+
const content = readFileSync(this.filePath, 'utf-8');
|
|
68
|
+
return this.parseCSV(content);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private parseCSV(content: string): Document[] {
|
|
72
|
+
const delimiter = this.options.delimiter || ',';
|
|
73
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
74
|
+
|
|
75
|
+
if (lines.length === 0) return [];
|
|
76
|
+
|
|
77
|
+
const headers = this.options.headers || this.parseLine(lines[0], delimiter);
|
|
78
|
+
const documents: Document[] = [];
|
|
79
|
+
|
|
80
|
+
const startIndex = this.options.headers ? 0 : 1;
|
|
81
|
+
|
|
82
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
83
|
+
const values = this.parseLine(lines[i], delimiter);
|
|
84
|
+
if (this.options.skipEmptyLines && values.every(v => !v.trim())) continue;
|
|
85
|
+
|
|
86
|
+
const obj: Record<string, string> = {};
|
|
87
|
+
headers.forEach((header, idx) => {
|
|
88
|
+
obj[header.trim()] = values[idx] || '';
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
documents.push({
|
|
92
|
+
pageContent: JSON.stringify(obj),
|
|
93
|
+
metadata: {
|
|
94
|
+
source: this.filePath,
|
|
95
|
+
type: 'csv',
|
|
96
|
+
row: i - startIndex + 1,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return documents;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private parseLine(line: string, delimiter: string): string[] {
|
|
105
|
+
const result: string[] = [];
|
|
106
|
+
let current = '';
|
|
107
|
+
let inQuotes = false;
|
|
108
|
+
|
|
109
|
+
for (const char of line) {
|
|
110
|
+
if (char === '"') {
|
|
111
|
+
inQuotes = !inQuotes;
|
|
112
|
+
} else if (char === delimiter && !inQuotes) {
|
|
113
|
+
result.push(current);
|
|
114
|
+
current = '';
|
|
115
|
+
} else {
|
|
116
|
+
current += char;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
result.push(current);
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* JSON File Loader
|
|
126
|
+
*/
|
|
127
|
+
export class JSONLoader implements BaseLoader {
|
|
128
|
+
constructor(
|
|
129
|
+
private filePath: string,
|
|
130
|
+
private options: {
|
|
131
|
+
key?: string; // If specified, extract array items from this key
|
|
132
|
+
} = {}
|
|
133
|
+
) {}
|
|
134
|
+
|
|
135
|
+
async load(): Promise<Document[]> {
|
|
136
|
+
const content = await readFile(this.filePath, 'utf-8');
|
|
137
|
+
return this.parseJSON(content);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
loadSync(): Document[] {
|
|
141
|
+
const content = readFileSync(this.filePath, 'utf-8');
|
|
142
|
+
return this.parseJSON(content);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private parseJSON(content: string): Document[] {
|
|
146
|
+
const data = JSON.parse(content);
|
|
147
|
+
|
|
148
|
+
if (this.options.key) {
|
|
149
|
+
const array = data[this.options.key];
|
|
150
|
+
if (Array.isArray(array)) {
|
|
151
|
+
return array.map((item, idx) => ({
|
|
152
|
+
pageContent: typeof item === 'string' ? item : JSON.stringify(item),
|
|
153
|
+
metadata: {
|
|
154
|
+
source: this.filePath,
|
|
155
|
+
type: 'json',
|
|
156
|
+
key: this.options.key,
|
|
157
|
+
index: idx,
|
|
158
|
+
},
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (Array.isArray(data)) {
|
|
164
|
+
return data.map((item, idx) => ({
|
|
165
|
+
pageContent: typeof item === 'string' ? item : JSON.stringify(item),
|
|
166
|
+
metadata: {
|
|
167
|
+
source: this.filePath,
|
|
168
|
+
type: 'json',
|
|
169
|
+
index: idx,
|
|
170
|
+
},
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return [{
|
|
175
|
+
pageContent: JSON.stringify(data),
|
|
176
|
+
metadata: {
|
|
177
|
+
source: this.filePath,
|
|
178
|
+
type: 'json',
|
|
179
|
+
},
|
|
180
|
+
}];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Auto-detect file type and load
|
|
186
|
+
*/
|
|
187
|
+
export async function loadDocument(filePath: string, options?: any): Promise<Document[]> {
|
|
188
|
+
const ext = extname(filePath).toLowerCase();
|
|
189
|
+
|
|
190
|
+
switch (ext) {
|
|
191
|
+
case '.txt':
|
|
192
|
+
case '.md':
|
|
193
|
+
case '.text':
|
|
194
|
+
return new TextLoader(filePath).load();
|
|
195
|
+
|
|
196
|
+
case '.csv':
|
|
197
|
+
return new CSVLoader(filePath, options?.csv).load();
|
|
198
|
+
|
|
199
|
+
case '.json':
|
|
200
|
+
return new JSONLoader(filePath, options?.json).load();
|
|
201
|
+
|
|
202
|
+
default:
|
|
203
|
+
// Default to text loader
|
|
204
|
+
return new TextLoader(filePath).load();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Load multiple files
|
|
210
|
+
*/
|
|
211
|
+
export async function loadDocuments(
|
|
212
|
+
filePaths: string[],
|
|
213
|
+
options?: any
|
|
214
|
+
): Promise<Document[]> {
|
|
215
|
+
const documents: Document[] = [];
|
|
216
|
+
|
|
217
|
+
for (const filePath of filePaths) {
|
|
218
|
+
const docs = await loadDocument(filePath, options);
|
|
219
|
+
documents.push(...docs);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return documents;
|
|
223
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Embeddings
|
|
3
|
+
*
|
|
4
|
+
* Google AI Gemini embeddings for text vectorization
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
|
|
10
|
+
export interface GoogleEmbeddingsOptions {
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
model?: string;
|
|
13
|
+
taskType?: 'RETRIEVAL_QUERY' | 'RETRIEVAL_DOCUMENT' | 'SEMANTIC_SIMILARITY' | 'CLASSIFICATION' | 'CLUSTERING';
|
|
14
|
+
title?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface EmbeddingResponse {
|
|
18
|
+
embedding: {
|
|
19
|
+
values: number[];
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Google Embeddings
|
|
25
|
+
*
|
|
26
|
+
* Uses Google's Generative Language API for embeddings
|
|
27
|
+
*/
|
|
28
|
+
export class GoogleEmbeddings {
|
|
29
|
+
readonly model: string;
|
|
30
|
+
readonly taskType: string;
|
|
31
|
+
readonly title?: string;
|
|
32
|
+
private apiKey: string;
|
|
33
|
+
private apiUrl = 'https://generativelanguage.googleapis.com/v1beta';
|
|
34
|
+
|
|
35
|
+
constructor(options: GoogleEmbeddingsOptions = {}) {
|
|
36
|
+
this.apiKey = options.apiKey || (typeof process !== 'undefined' ? (process as any).env?.GEMINI_API_KEY : '') || '';
|
|
37
|
+
this.model = options.model || 'text-embedding-004';
|
|
38
|
+
this.taskType = options.taskType || 'RETRIEVAL_DOCUMENT';
|
|
39
|
+
this.title = options.title;
|
|
40
|
+
|
|
41
|
+
if (!this.apiKey) {
|
|
42
|
+
logger.warn('[GoogleEmbeddings] No API key provided. Set GEMINI_API_KEY env var or pass apiKey option.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Embed a single text
|
|
48
|
+
*/
|
|
49
|
+
async embedQuery(text: string): Promise<number[]> {
|
|
50
|
+
return this.embed([text]).then(res => res[0]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Embed multiple texts
|
|
55
|
+
*/
|
|
56
|
+
async embedDocuments(texts: string[]): Promise<number[][]> {
|
|
57
|
+
return this.embed(texts);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private async embed(texts: string[]): Promise<number[][]> {
|
|
61
|
+
if (!this.apiKey) {
|
|
62
|
+
throw new Error('Google API key required. Set GEMINI_API_KEY or pass apiKey option.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const embeddings: number[][] = [];
|
|
66
|
+
|
|
67
|
+
// Google API allows up to 100 inputs per request
|
|
68
|
+
const batchSize = 100;
|
|
69
|
+
|
|
70
|
+
for (let i = 0; i < texts.length; i += batchSize) {
|
|
71
|
+
const batch = texts.slice(i, i + batchSize);
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const requests = batch.map((content, idx) => ({
|
|
75
|
+
model: `models/${this.model}`,
|
|
76
|
+
content: { role: 'user', parts: [{ text: content }] },
|
|
77
|
+
taskType: this.taskType,
|
|
78
|
+
title: this.title,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
const response = await axios.post(
|
|
82
|
+
`${this.apiUrl}/embedContent:batchEmbedContents?key=${this.apiKey}`,
|
|
83
|
+
{ requests },
|
|
84
|
+
{
|
|
85
|
+
headers: { 'Content-Type': 'application/json' },
|
|
86
|
+
timeout: 60000,
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const results = response.data.embeddings || [];
|
|
91
|
+
for (let j = 0; j < results.length; j++) {
|
|
92
|
+
const result = results[j];
|
|
93
|
+
if (result.embedding?.values) {
|
|
94
|
+
embeddings.push(result.embedding.values);
|
|
95
|
+
} else {
|
|
96
|
+
// Fallback: generate random embedding
|
|
97
|
+
logger.warn(`[GoogleEmbeddings] Empty embedding for batch ${Math.floor(i / batchSize)}, index ${j}`);
|
|
98
|
+
embeddings.push(new Array(768).fill(0));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
logger.error(`[GoogleEmbeddings] Error embedding batch: ${error.message}`);
|
|
103
|
+
// Return zero embeddings on error
|
|
104
|
+
for (let j = 0; j < batch.length; j++) {
|
|
105
|
+
embeddings.push(new Array(768).fill(0));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return embeddings;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Factory function
|
|
116
|
+
*/
|
|
117
|
+
export function createGoogleEmbeddings(options?: GoogleEmbeddingsOptions): GoogleEmbeddings {
|
|
118
|
+
return new GoogleEmbeddings(options);
|
|
119
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Embeddings
|
|
3
|
+
*
|
|
4
|
+
* Zero-cost, completely offline embedding generation
|
|
5
|
+
* Uses a simple hash-based approach for demonstration
|
|
6
|
+
* For production, use transformers.js or ONNX runtime
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { logger } from '../utils/logger.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Local Embeddings
|
|
13
|
+
*
|
|
14
|
+
* Generates embeddings locally without API calls.
|
|
15
|
+
* Uses a deterministic hash-based approach for consistent results.
|
|
16
|
+
* For production use, integrate with transformers.js or ONNX runtime.
|
|
17
|
+
*/
|
|
18
|
+
export class LocalEmbeddings {
|
|
19
|
+
readonly dimensions: number;
|
|
20
|
+
private modelName: string;
|
|
21
|
+
|
|
22
|
+
constructor(options: { dimensions?: number; modelName?: string } = {}) {
|
|
23
|
+
this.dimensions = options.dimensions || 384;
|
|
24
|
+
this.modelName = options.modelName || 'local-hash';
|
|
25
|
+
logger.info(`[LocalEmbeddings] Initialized with ${this.dimensions} dimensions`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Generate embedding using a simple hash-based approach
|
|
30
|
+
* This is NOT suitable for production semantic search
|
|
31
|
+
* but provides consistent results for testing
|
|
32
|
+
*/
|
|
33
|
+
private generateHashEmbedding(text: string): number[] {
|
|
34
|
+
const embedding = new Array(this.dimensions).fill(0);
|
|
35
|
+
|
|
36
|
+
// Simple hash to generate consistent embedding
|
|
37
|
+
for (let i = 0; i < text.length; i++) {
|
|
38
|
+
const char = text.charCodeAt(i);
|
|
39
|
+
const idx1 = i % this.dimensions;
|
|
40
|
+
const idx2 = (i * 31 + char) % this.dimensions;
|
|
41
|
+
|
|
42
|
+
embedding[idx1] += char / text.length;
|
|
43
|
+
embedding[idx2] += char / text.length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Normalize
|
|
47
|
+
const magnitude = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
|
|
48
|
+
if (magnitude > 0) {
|
|
49
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
50
|
+
embedding[i] /= magnitude;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return embedding;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Embed a single text
|
|
59
|
+
*/
|
|
60
|
+
async embedQuery(text: string): Promise<number[]> {
|
|
61
|
+
return this.generateHashEmbedding(text);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Embed multiple texts
|
|
66
|
+
*/
|
|
67
|
+
async embedDocuments(texts: string[]): Promise<number[][]> {
|
|
68
|
+
return texts.map(text => this.generateHashEmbedding(text));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Batch embed
|
|
73
|
+
*/
|
|
74
|
+
async embed(texts: string[]): Promise<number[][]> {
|
|
75
|
+
return this.embedDocuments(texts);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Factory function
|
|
81
|
+
*/
|
|
82
|
+
export function createLocalEmbeddings(options?: {
|
|
83
|
+
dimensions?: number;
|
|
84
|
+
modelName?: string;
|
|
85
|
+
}): LocalEmbeddings {
|
|
86
|
+
return new LocalEmbeddings(options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Mock HuggingFace Embeddings (for compatibility)
|
|
91
|
+
* In production, use @xenova/transformers
|
|
92
|
+
*/
|
|
93
|
+
export class HuggingFaceEmbeddings {
|
|
94
|
+
readonly model: string;
|
|
95
|
+
readonly device: string;
|
|
96
|
+
readonly normalize: boolean;
|
|
97
|
+
|
|
98
|
+
constructor(options: {
|
|
99
|
+
model?: string;
|
|
100
|
+
device?: string;
|
|
101
|
+
normalize?: boolean;
|
|
102
|
+
} = {}) {
|
|
103
|
+
this.model = options.model || 'sentence-transformers/all-MiniLM-L6-v2';
|
|
104
|
+
this.device = options.device || 'cpu';
|
|
105
|
+
this.normalize = options.normalize !== false;
|
|
106
|
+
|
|
107
|
+
logger.info(`[HuggingFaceEmbeddings] Initialized (mock). For real embeddings, install @xenova/transformers`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async embedQuery(text: string): Promise<number[]> {
|
|
111
|
+
// Mock implementation
|
|
112
|
+
return new LocalEmbeddings().embedQuery(text);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async embedDocuments(texts: string[]): Promise<number[][]> {
|
|
116
|
+
return new LocalEmbeddings().embedDocuments(texts);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLMJudge - Evaluate LLM responses
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseChatModel, Message } from '../core/types.js';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Evaluation Criteria
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
export enum EvalCriteria {
|
|
13
|
+
FAITHFULNESS = 'faithfulness',
|
|
14
|
+
RELEVANCE = 'relevance',
|
|
15
|
+
TOXICITY = 'toxicity',
|
|
16
|
+
COHERENCE = 'coherence',
|
|
17
|
+
ACCURACY = 'accuracy',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EvalResult {
|
|
21
|
+
score: number;
|
|
22
|
+
explanation: string;
|
|
23
|
+
passed: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// LLM Judge
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
const EVAL_PROMPT = `You are an impartial, strict evaluator. Your job is to grade the Assistant's response
|
|
31
|
+
based on the following criteria: {criteria}.
|
|
32
|
+
|
|
33
|
+
Question asked by User:
|
|
34
|
+
"{question}"
|
|
35
|
+
|
|
36
|
+
Context provided to Assistant (if any):
|
|
37
|
+
"{context}"
|
|
38
|
+
|
|
39
|
+
Assistant's Response:
|
|
40
|
+
"{response}"
|
|
41
|
+
|
|
42
|
+
Evaluate the response. Output strictly in the following JSON schema:
|
|
43
|
+
{{
|
|
44
|
+
"score": <int from 1 to 10>,
|
|
45
|
+
"explanation": "<brief reason for the score>",
|
|
46
|
+
"passed": <boolean true if score >= 7 else false>
|
|
47
|
+
}}
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
export class LLMJudge {
|
|
51
|
+
private judgeLLM: BaseChatModel;
|
|
52
|
+
|
|
53
|
+
constructor(judgeLLM: BaseChatModel) {
|
|
54
|
+
this.judgeLLM = judgeLLM;
|
|
55
|
+
logger.info('LLMJudge ready. Ready to evaluate responses.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async evaluate(
|
|
59
|
+
question: string,
|
|
60
|
+
response: string,
|
|
61
|
+
criteria: EvalCriteria,
|
|
62
|
+
context: string = ''
|
|
63
|
+
): Promise<EvalResult> {
|
|
64
|
+
const prompt = EVAL_PROMPT
|
|
65
|
+
.replace('{criteria}', criteria as string)
|
|
66
|
+
.replace('{question}', question)
|
|
67
|
+
.replace('{context}', context)
|
|
68
|
+
.replace('{response}', response);
|
|
69
|
+
|
|
70
|
+
const messages: Message[] = [
|
|
71
|
+
{ role: 'system', content: 'You are a JSON grading API.' },
|
|
72
|
+
{ role: 'user', content: prompt },
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const result = await this.judgeLLM.invoke(messages, {
|
|
77
|
+
responseFormat: { type: 'json_object' }
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const content = result.content.trim();
|
|
81
|
+
const parsed = JSON.parse(content);
|
|
82
|
+
|
|
83
|
+
logger.debug(`[Judge] Score: ${parsed.score}/10 - Passed: ${parsed.passed}`);
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
score: parsed.score ?? 0,
|
|
87
|
+
explanation: parsed.explanation ?? '',
|
|
88
|
+
passed: parsed.passed ?? false,
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error(`Evaluation failed: ${error}`);
|
|
92
|
+
return {
|
|
93
|
+
score: 0,
|
|
94
|
+
explanation: String(error),
|
|
95
|
+
passed: false,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazlo - The Anti-Framework for JavaScript/TypeScript
|
|
3
|
+
*
|
|
4
|
+
* A production-grade AI framework that prioritizes performance, transparency, and simplicity.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Core Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
export * from './core/types.js';
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Providers
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
export { OpenAI, createOpenAI } from './providers/openai.js';
|
|
18
|
+
export { Ollama, createOllama } from './providers/ollama.js';
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Chains
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export { LLMChain, SequentialChain, PromptTemplate } from './chains/llmchain.js';
|
|
25
|
+
export { RetrievalQAChain, createRetrievalChain } from './chains/rag.js';
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Router
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
export { SmartRouter } from './router/smartrouter.js';
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Cache
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
export { SemanticCache } from './cache/semantic.js';
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Memory
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
export { BufferMemory, TokenBudgetMemory } from './memory/buffer.js';
|
|
44
|
+
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Tools
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
49
|
+
export { Tool, tool, createToolDecorator, defineTool, calculator, search, weather, KeiroSearch } from './tools/index.js';
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Tracing
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
export { tracer, Tracer } from './tracing/tracer.js';
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Evals
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
export { LLMJudge, EvalCriteria } from './evals/judge.js';
|
|
62
|
+
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Text Splitters
|
|
65
|
+
// ============================================================================
|
|
66
|
+
|
|
67
|
+
export { CharacterTextSplitter, RecursiveCharacterTextSplitter, createCharacterSplitter, createRecursiveSplitter } from './text_splitters/index.js';
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// Vector Stores
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
export { InMemoryVectorStore, ChromaVectorStore, SQLiteVectorStore, createVectorStore, createChromaVectorStore, createSQLiteVectorStore } from './vectorstores/index.js';
|
|
74
|
+
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// Document Loaders
|
|
77
|
+
// ============================================================================
|
|
78
|
+
|
|
79
|
+
export { TextLoader, CSVLoader, JSONLoader, loadDocument, loadDocuments } from './document_loaders/index.js';
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Embeddings
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
export { GoogleEmbeddings, createGoogleEmbeddings } from './embeddings/google.js';
|
|
86
|
+
export { LocalEmbeddings, HuggingFaceEmbeddings, createLocalEmbeddings } from './embeddings/local.js';
|
|
87
|
+
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Output Parsers
|
|
90
|
+
// ============================================================================
|
|
91
|
+
|
|
92
|
+
export { JSONOutputParser, XMLOutputParser, CommaSeparatedListParser, MarkdownCodeBlockParser, ToolCallParser, createJSONParser, createXMLParser, createListParser, createMarkdownParser } from './parsers/output.js';
|
|
93
|
+
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// Prompt Registry
|
|
96
|
+
// ============================================================================
|
|
97
|
+
|
|
98
|
+
export { PromptRegistry, SimplePromptTemplate, createPromptRegistry } from './prompts/registry.js';
|
|
99
|
+
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// Retrievers
|
|
102
|
+
// ============================================================================
|
|
103
|
+
|
|
104
|
+
export { ContextualCompressionRetriever, ParentDocumentRetriever, EnsembleRetriever, createVectorStoreRetriever } from './retrievers/index.js';
|
|
105
|
+
export type { BaseRetriever } from './retrievers/index.js';
|
|
106
|
+
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Utils
|
|
109
|
+
// ============================================================================
|
|
110
|
+
|
|
111
|
+
export { logger } from './utils/logger.js';
|
|
112
|
+
export { getPricing, setPricing, calculateCost, estimateCost, estimateTokens } from './utils/pricing.js';
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Initialize
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
import { loadEnvPricing } from './utils/pricing.js';
|
|
119
|
+
loadEnvPricing();
|
|
120
|
+
|
|
121
|
+
console.log('⚡ Lazlo JS loaded. The Anti-Framework.');
|