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
package/.env.example
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# OpenAI API Key (required for OpenAI provider)
|
|
2
|
+
OPENAI_API_KEY=sk-your-openai-key-here
|
|
3
|
+
|
|
4
|
+
# Keiro Search API (optional - for web search tool)
|
|
5
|
+
KEIRO_API_KEY=your-keiro-key
|
|
6
|
+
|
|
7
|
+
# Custom model pricing (optional)
|
|
8
|
+
# Format: LAZLO_PRICING_model_name=input_cost,output_cost
|
|
9
|
+
# LAZLO_PRICING_gpt4=2.5,10
|
package/README.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Lazlo JS
|
|
2
|
+
|
|
3
|
+
The Anti-Framework for JavaScript/TypeScript - A production-grade AI framework that prioritizes performance, transparency, and simplicity.
|
|
4
|
+
|
|
5
|
+
## Why Lazlo?
|
|
6
|
+
|
|
7
|
+
- **No Black Magic**: When you use a tool, you see the JSON being parsed. Debugging is straightforward JavaScript.
|
|
8
|
+
- **Zero Bloat**: Core Lazlo uses just `axios` and `zod`. Everything else is optional.
|
|
9
|
+
- **Production Built-In**: Caching, routing, and tracing are built directly into Lazlo, locally and securely.
|
|
10
|
+
- **Protocols over Inheritance**: Duck typing works out of the box. If your class implements `invoke()`, it's an LLM.
|
|
11
|
+
- **Full RAG Pipeline**: Document loaders, embeddings, vector stores, and retrievers built-in.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install lazlo
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Environment Setup
|
|
20
|
+
|
|
21
|
+
Create a `.env` file in your project root:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Required for OpenAI provider
|
|
25
|
+
OPENAI_API_KEY=sk-your-openai-key-here
|
|
26
|
+
|
|
27
|
+
# Required for Google embeddings/Gemini
|
|
28
|
+
GEMINI_API_KEY=your-gemini-key
|
|
29
|
+
|
|
30
|
+
# Required for Ollama (local models)
|
|
31
|
+
# No API key needed - runs locally
|
|
32
|
+
|
|
33
|
+
# Optional: Keiro Search API
|
|
34
|
+
KEIRO_API_KEY=your-keiro-key
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { OpenAI, LLMChain, PromptTemplate } from 'lazlo';
|
|
41
|
+
|
|
42
|
+
// Create an LLM - key from OPENAI_API_KEY env var
|
|
43
|
+
const llm = new OpenAI();
|
|
44
|
+
|
|
45
|
+
// Create a chain
|
|
46
|
+
const chain = new LLMChain({
|
|
47
|
+
llm,
|
|
48
|
+
prompt: new PromptTemplate('What is {topic}?'),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Run it
|
|
52
|
+
const result = await chain.invoke({ topic: 'quantum computing' });
|
|
53
|
+
console.log(result.text);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Full Feature List
|
|
57
|
+
|
|
58
|
+
### Providers
|
|
59
|
+
- **OpenAI** - GPT-4, GPT-4o, GPT-4o-mini, etc.
|
|
60
|
+
- **Ollama** - Local LLMs (Llama3.2, Mistral, etc.)
|
|
61
|
+
|
|
62
|
+
### Embeddings
|
|
63
|
+
- **OpenAIEmbeddings** - OpenAI text embeddings
|
|
64
|
+
- **GoogleEmbeddings** - Google Gemini embeddings
|
|
65
|
+
- **LocalEmbeddings** - Zero-cost offline embeddings
|
|
66
|
+
|
|
67
|
+
### Vector Stores
|
|
68
|
+
- **InMemoryVectorStore** - Fast prototyping
|
|
69
|
+
- **ChromaVectorStore** - Production disk persistence
|
|
70
|
+
- **SQLiteVectorStore** - Zero-infrastructure, single file
|
|
71
|
+
|
|
72
|
+
### Document Loaders
|
|
73
|
+
- **TextLoader** - .txt, .md files
|
|
74
|
+
- **CSVLoader** - CSV with custom delimiters
|
|
75
|
+
- **JSONLoader** - JSON with key extraction
|
|
76
|
+
- Auto-detection of file types
|
|
77
|
+
|
|
78
|
+
### Chains
|
|
79
|
+
- **LLMChain** - Basic prompt → LLM → output
|
|
80
|
+
- **SequentialChain** - Multi-step pipelines
|
|
81
|
+
- **RetrievalQAChain** - RAG with context
|
|
82
|
+
|
|
83
|
+
### Smart Routing
|
|
84
|
+
- Auto-route simple queries to cheap models
|
|
85
|
+
- Complex queries to smart models
|
|
86
|
+
|
|
87
|
+
### Caching
|
|
88
|
+
- **SemanticCache** - Cosine similarity cache hits
|
|
89
|
+
|
|
90
|
+
### Memory
|
|
91
|
+
- **BufferMemory** - Conversation history
|
|
92
|
+
- **TokenBudgetMemory** - Auto-summarization at limit
|
|
93
|
+
|
|
94
|
+
### Tools
|
|
95
|
+
- **@tool decorator** - Custom function tools
|
|
96
|
+
- **calculator** - Math expression evaluator
|
|
97
|
+
- **search** - Web search (via Keiro)
|
|
98
|
+
- **weather** - Weather data
|
|
99
|
+
|
|
100
|
+
### Tracing
|
|
101
|
+
- Built-in observability, no SaaS needed
|
|
102
|
+
|
|
103
|
+
### Evals
|
|
104
|
+
- **LLMJudge** - Automated response evaluation
|
|
105
|
+
|
|
106
|
+
### Output Parsers
|
|
107
|
+
- **JSONOutputParser** - Parse JSON from text
|
|
108
|
+
- **XMLOutputParser** - Extract XML tags
|
|
109
|
+
- **CommaSeparatedListParser** - Split lists
|
|
110
|
+
- **MarkdownCodeBlockParser** - Extract code blocks
|
|
111
|
+
|
|
112
|
+
### Prompt Registry
|
|
113
|
+
- Load prompts from YAML files
|
|
114
|
+
- Version support (@v1, @v2)
|
|
115
|
+
|
|
116
|
+
### Retrievers
|
|
117
|
+
- **ContextualCompressionRetriever** - Compress docs by context
|
|
118
|
+
- **ParentDocumentRetriever** - Get full docs from chunks
|
|
119
|
+
- **EnsembleRetriever** - Combine multiple retrievers
|
|
120
|
+
- **createVectorStoreRetriever** - Easy vector RAG
|
|
121
|
+
|
|
122
|
+
## Example: Full RAG Pipeline
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import {
|
|
126
|
+
OpenAI,
|
|
127
|
+
InMemoryVectorStore,
|
|
128
|
+
TextLoader,
|
|
129
|
+
CharacterTextSplitter,
|
|
130
|
+
LLMChain,
|
|
131
|
+
PromptTemplate,
|
|
132
|
+
createVectorStoreRetriever
|
|
133
|
+
} from 'lazlo';
|
|
134
|
+
|
|
135
|
+
// 1. Load documents
|
|
136
|
+
const loader = new TextLoader('./docs.txt');
|
|
137
|
+
const docs = await loader.load();
|
|
138
|
+
|
|
139
|
+
// 2. Split into chunks
|
|
140
|
+
const splitter = new CharacterTextSplitter({ chunkSize: 1000 });
|
|
141
|
+
const chunks = await splitter.splitDocuments(docs);
|
|
142
|
+
|
|
143
|
+
// 3. Create vector store
|
|
144
|
+
const embeddings = new OpenAI(); // Uses OpenAI embeddings
|
|
145
|
+
const vectorStore = new InMemoryVectorStore(embeddings);
|
|
146
|
+
await vectorStore.addDocuments(chunks);
|
|
147
|
+
|
|
148
|
+
// 4. Create retriever
|
|
149
|
+
const retriever = createVectorStoreRetriever(vectorStore);
|
|
150
|
+
|
|
151
|
+
// 5. Create RAG chain
|
|
152
|
+
const ragChain = new LLMChain({
|
|
153
|
+
llm: new OpenAI(),
|
|
154
|
+
prompt: new PromptTemplate('Context: {context}\nQuestion: {question}\nAnswer:'),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// 6. Run with retrieval
|
|
158
|
+
const retrievedDocs = await retriever.getRelevantDocuments('What is Lazlo?');
|
|
159
|
+
const context = retrievedDocs.map(d => d.pageContent).join('\n');
|
|
160
|
+
const result = await ragChain.invoke({ question: 'What is Lazlo?', context });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Example: Prompt Registry
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { PromptRegistry } from 'lazlo';
|
|
167
|
+
|
|
168
|
+
const registry = new PromptRegistry('./prompts');
|
|
169
|
+
|
|
170
|
+
// Register a prompt
|
|
171
|
+
registry.register('rag_qa', {
|
|
172
|
+
template: 'Context: {context}\nQuestion: {question}',
|
|
173
|
+
description: 'RAG QA prompt',
|
|
174
|
+
version: '1.0.0',
|
|
175
|
+
variables: ['context', 'question'],
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Load with version
|
|
179
|
+
const template = registry.load('rag_qa@v1');
|
|
180
|
+
const formatted = registry.format(template, { context: '...', question: '...' });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Example: Output Parsing
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { JSONOutputParser } from 'lazlo';
|
|
187
|
+
|
|
188
|
+
const parser = new JSONOutputParser();
|
|
189
|
+
const result = await parser.parse('{"name": "John", "age": 30}');
|
|
190
|
+
// Returns: { name: "John", age: 30 }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Example: Ensemble Retrieval
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import {
|
|
197
|
+
EnsembleRetriever,
|
|
198
|
+
createVectorStoreRetriever,
|
|
199
|
+
InMemoryVectorStore
|
|
200
|
+
} from 'lazlo';
|
|
201
|
+
|
|
202
|
+
const embeddings = new OpenAI();
|
|
203
|
+
const store1 = new InMemoryVectorStore(embeddings);
|
|
204
|
+
const store2 = new InMemoryVectorStore(embeddings);
|
|
205
|
+
|
|
206
|
+
// ... add different docs to each store ...
|
|
207
|
+
|
|
208
|
+
const retriever = new EnsembleRetriever([
|
|
209
|
+
{ retriever: createVectorStoreRetriever(store1), weight: 0.7 },
|
|
210
|
+
{ retriever: createVectorStoreRetriever(store2), weight: 0.3 },
|
|
211
|
+
]);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Cost Estimation
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { LLMChain, PromptTemplate, OpenAI } from 'lazlo';
|
|
218
|
+
|
|
219
|
+
const chain = new LLMChain({
|
|
220
|
+
llm: new OpenAI('gpt-4o'),
|
|
221
|
+
prompt: new PromptTemplate('Write about {topic}'),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const estimate = chain.estimateCost({ topic: 'AI' });
|
|
225
|
+
console.log(`Estimated cost: $${estimate.estimatedCostUsd}`);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## API Reference
|
|
229
|
+
|
|
230
|
+
### OpenAI
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
new OpenAI(apiKey?: string, defaultModel?: string, options?: {
|
|
234
|
+
temperature?: number,
|
|
235
|
+
maxTokens?: number,
|
|
236
|
+
topP?: number,
|
|
237
|
+
})
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Ollama
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
new Ollama(options?: {
|
|
244
|
+
model?: string,
|
|
245
|
+
baseUrl?: string,
|
|
246
|
+
temperature?: number,
|
|
247
|
+
numCtx?: number,
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Vector Stores
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
new InMemoryVectorStore(embeddings)
|
|
255
|
+
new ChromaVectorStore({ embeddings, collectionName?: string })
|
|
256
|
+
new SQLiteVectorStore({ embeddings, dbPath?: string })
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Document Loaders
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
new TextLoader(filePath: string)
|
|
263
|
+
new CSVLoader(filePath: string, options?: { delimiter?: string })
|
|
264
|
+
new JSONLoader(filePath: string, options?: { key?: string })
|
|
265
|
+
loadDocument(filePath: string): Promise<Document[]>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Embeddings
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
new OpenAIEmbeddings(options?: { apiKey?: string, model?: string })
|
|
272
|
+
new GoogleEmbeddings(options?: { apiKey?: string, model?: string })
|
|
273
|
+
new LocalEmbeddings(options?: { dimensions?: number })
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Cache - Cache LLM responses with semantic similarity
|
|
3
|
+
*/
|
|
4
|
+
export interface SemanticCacheOptions {
|
|
5
|
+
threshold?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class SemanticCache {
|
|
8
|
+
private store;
|
|
9
|
+
private threshold;
|
|
10
|
+
private hits;
|
|
11
|
+
private misses;
|
|
12
|
+
private tokensSaved;
|
|
13
|
+
constructor(options?: SemanticCacheOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Look up a cached response
|
|
16
|
+
*/
|
|
17
|
+
lookup(prompt: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Store a response in the cache
|
|
20
|
+
*/
|
|
21
|
+
put(prompt: string, response: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Wrap an LLM to use caching
|
|
24
|
+
*/
|
|
25
|
+
wrap<T extends {
|
|
26
|
+
invoke(prompt: string): Promise<any>;
|
|
27
|
+
}>(llm: T): T & {
|
|
28
|
+
invoke(prompt: string): Promise<any>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Print cache statistics
|
|
32
|
+
*/
|
|
33
|
+
printStats(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Clear the cache
|
|
36
|
+
*/
|
|
37
|
+
clear(): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/cache/semantic.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6DH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,WAAW,CAAK;gBAEZ,OAAO,GAAE,oBAAyB;IAK9C;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA2BrC;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAM3C;;OAEG;IACH,IAAI,CAAC,CAAC,SAAS;QAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;KAAE,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG;QAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;KAAE;IAsB9G;;OAEG;IACH,UAAU,IAAI,IAAI;IAkBlB;;OAEG;IACH,KAAK,IAAI,IAAI;CAOd"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Cache - Cache LLM responses with semantic similarity
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Cosine Similarity
|
|
7
|
+
// ============================================================================
|
|
8
|
+
function cosineSimilarity(v1, v2) {
|
|
9
|
+
const dot = v1.reduce((sum, a, i) => sum + a * v2[i], 0);
|
|
10
|
+
const norm1 = Math.sqrt(v1.reduce((sum, a) => sum + a * a, 0));
|
|
11
|
+
const norm2 = Math.sqrt(v2.reduce((sum, b) => sum + b * b, 0));
|
|
12
|
+
if (norm1 === 0 || norm2 === 0)
|
|
13
|
+
return 0;
|
|
14
|
+
return dot / (norm1 * norm2);
|
|
15
|
+
}
|
|
16
|
+
// Simple hash-based embedding (for demo - in production use real embeddings)
|
|
17
|
+
// This creates a deterministic "embedding" from the text
|
|
18
|
+
function simpleEmbedding(text) {
|
|
19
|
+
const hash = new Map();
|
|
20
|
+
const words = text.toLowerCase().split(/\s+/);
|
|
21
|
+
// Create a simple bag-of-words embedding
|
|
22
|
+
for (let i = 0; i < 384; i++) {
|
|
23
|
+
hash.set(String(i), 0);
|
|
24
|
+
}
|
|
25
|
+
words.forEach((word, idx) => {
|
|
26
|
+
const hash1 = (word.charCodeAt(0) * 31 + idx) % 384;
|
|
27
|
+
const hash2 = (word.length * 17 + idx) % 384;
|
|
28
|
+
hash.set(String(hash1), (hash.get(String(hash1)) ?? 0) + 1);
|
|
29
|
+
hash.set(String(hash2), (hash.get(String(hash2)) ?? 0) + 0.5);
|
|
30
|
+
});
|
|
31
|
+
// Normalize
|
|
32
|
+
const embedding = [];
|
|
33
|
+
let norm = 0;
|
|
34
|
+
for (let i = 0; i < 384; i++) {
|
|
35
|
+
const val = hash.get(String(i)) ?? 0;
|
|
36
|
+
embedding.push(val);
|
|
37
|
+
norm += val * val;
|
|
38
|
+
}
|
|
39
|
+
norm = Math.sqrt(norm);
|
|
40
|
+
return embedding.map(v => v / (norm || 1));
|
|
41
|
+
}
|
|
42
|
+
export class SemanticCache {
|
|
43
|
+
store = [];
|
|
44
|
+
threshold;
|
|
45
|
+
hits = 0;
|
|
46
|
+
misses = 0;
|
|
47
|
+
tokensSaved = 0;
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.threshold = options.threshold ?? 0.92;
|
|
50
|
+
logger.info(`SemanticCache ready. Threshold: ${this.threshold}`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Look up a cached response
|
|
54
|
+
*/
|
|
55
|
+
lookup(prompt) {
|
|
56
|
+
if (this.store.length === 0) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const queryEmbedding = simpleEmbedding(prompt);
|
|
60
|
+
let bestScore = 0;
|
|
61
|
+
let bestResponse = null;
|
|
62
|
+
for (const entry of this.store) {
|
|
63
|
+
const score = cosineSimilarity(queryEmbedding, entry.embedding);
|
|
64
|
+
if (score > bestScore) {
|
|
65
|
+
bestScore = score;
|
|
66
|
+
bestResponse = entry.response;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (bestScore >= this.threshold) {
|
|
70
|
+
logger.info(`[SemanticCache] CACHE HIT (similarity=${bestScore.toFixed(3)}). Skipping LLM call.`);
|
|
71
|
+
this.hits++;
|
|
72
|
+
this.tokensSaved += bestResponse.length / 4;
|
|
73
|
+
return bestResponse;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Store a response in the cache
|
|
79
|
+
*/
|
|
80
|
+
put(prompt, response) {
|
|
81
|
+
const embedding = simpleEmbedding(prompt);
|
|
82
|
+
this.store.push({ prompt, response, embedding });
|
|
83
|
+
logger.debug(`[SemanticCache] Stored response for: ${prompt.slice(0, 50)}...`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Wrap an LLM to use caching
|
|
87
|
+
*/
|
|
88
|
+
wrap(llm) {
|
|
89
|
+
const cache = this;
|
|
90
|
+
const cachedInvoke = async function (prompt) {
|
|
91
|
+
const cached = cache.lookup(prompt);
|
|
92
|
+
if (cached !== null) {
|
|
93
|
+
return cached;
|
|
94
|
+
}
|
|
95
|
+
cache.misses++;
|
|
96
|
+
logger.debug('[SemanticCache] CACHE MISS. Calling LLM.');
|
|
97
|
+
const response = await llm.invoke(prompt);
|
|
98
|
+
const responseStr = typeof response === 'string' ? response : response.content ?? '';
|
|
99
|
+
cache.put(prompt, responseStr);
|
|
100
|
+
return response;
|
|
101
|
+
};
|
|
102
|
+
return Object.assign(cachedInvoke, llm);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Print cache statistics
|
|
106
|
+
*/
|
|
107
|
+
printStats() {
|
|
108
|
+
const total = this.hits + this.misses;
|
|
109
|
+
const hitRate = total > 0 ? (this.hits / total * 100).toFixed(1) : '0.0';
|
|
110
|
+
const costSaved = (this.tokensSaved / 1000 * 0.002).toFixed(4);
|
|
111
|
+
console.log(`
|
|
112
|
+
${'='.repeat(50)}
|
|
113
|
+
Lazlo SemanticCache Stats
|
|
114
|
+
${'='.repeat(50)}
|
|
115
|
+
Total calls : ${total}
|
|
116
|
+
Cache hits : ${this.hits} (${hitRate}%)
|
|
117
|
+
Cache misses: ${this.misses}
|
|
118
|
+
Est. tokens saved : ~${this.tokensSaved.toLocaleString()}
|
|
119
|
+
Est. cost avoided : ~$${costSaved}
|
|
120
|
+
${'='.repeat(50)}
|
|
121
|
+
`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Clear the cache
|
|
125
|
+
*/
|
|
126
|
+
clear() {
|
|
127
|
+
this.store = [];
|
|
128
|
+
this.hits = 0;
|
|
129
|
+
this.misses = 0;
|
|
130
|
+
this.tokensSaved = 0;
|
|
131
|
+
logger.info('SemanticCache cleared.');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=semantic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../src/cache/semantic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLMChain - Simple prompt chaining
|
|
3
|
+
*/
|
|
4
|
+
import { BaseChatModel, ChainInputs, ChainOutputs } from '../core/types.js';
|
|
5
|
+
export declare class PromptTemplate {
|
|
6
|
+
private template;
|
|
7
|
+
private inputVariables;
|
|
8
|
+
constructor(template: string);
|
|
9
|
+
format(values: Record<string, unknown>): string;
|
|
10
|
+
get inputVars(): string[];
|
|
11
|
+
}
|
|
12
|
+
export interface LLMChainOptions {
|
|
13
|
+
llm: BaseChatModel;
|
|
14
|
+
prompt: PromptTemplate;
|
|
15
|
+
outputKey?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CostEstimate {
|
|
18
|
+
estimatedTokensIn: number;
|
|
19
|
+
estimatedTokensOut: number;
|
|
20
|
+
estimatedCostUsd: number;
|
|
21
|
+
estimatedLatencyMs: number;
|
|
22
|
+
model: string;
|
|
23
|
+
pricing: {
|
|
24
|
+
input: number;
|
|
25
|
+
output: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare class LLMChain {
|
|
29
|
+
private llm;
|
|
30
|
+
private prompt;
|
|
31
|
+
private outputKey;
|
|
32
|
+
constructor(options: LLMChainOptions);
|
|
33
|
+
/**
|
|
34
|
+
* Estimate cost before running
|
|
35
|
+
*/
|
|
36
|
+
estimateCost(inputs: ChainInputs, model?: string): CostEstimate;
|
|
37
|
+
/**
|
|
38
|
+
* Invoke the chain synchronously
|
|
39
|
+
*/
|
|
40
|
+
invoke(inputs: ChainInputs): Promise<ChainOutputs>;
|
|
41
|
+
/**
|
|
42
|
+
* Stream the response
|
|
43
|
+
*/
|
|
44
|
+
stream(inputs: ChainInputs): AsyncGenerator<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Async invoke
|
|
47
|
+
*/
|
|
48
|
+
ainvoke(inputs: ChainInputs): Promise<ChainOutputs>;
|
|
49
|
+
/**
|
|
50
|
+
* Async stream
|
|
51
|
+
*/
|
|
52
|
+
astream(inputs: ChainInputs): AsyncGenerator<string>;
|
|
53
|
+
}
|
|
54
|
+
export declare class SequentialChain {
|
|
55
|
+
private chains;
|
|
56
|
+
private inputVariables;
|
|
57
|
+
private outputVariables;
|
|
58
|
+
constructor(options: {
|
|
59
|
+
chains: LLMChain[];
|
|
60
|
+
inputVariables: string[];
|
|
61
|
+
outputVariables: string[];
|
|
62
|
+
});
|
|
63
|
+
invoke(inputs: ChainInputs): Promise<ChainOutputs>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=llmchain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmchain.d.ts","sourceRoot":"","sources":["../../src/chains/llmchain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAW,WAAW,EAAE,YAAY,EAAkB,MAAM,kBAAkB,CAAC;AAQrG,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAW;gBAErB,QAAQ,EAAE,MAAM;IAQ5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAc/C,IAAI,SAAS,IAAI,MAAM,EAAE,CAExB;CACF;AAMD,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,eAAe;IAMpC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY;IAwB/D;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAwBxD;;OAEG;IACI,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC;IAW1D;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIzD;;OAEG;IACI,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC;CAG5D;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,eAAe,CAAW;gBAEtB,OAAO,EAAE;QACnB,MAAM,EAAE,QAAQ,EAAE,CAAC;QACnB,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,eAAe,EAAE,MAAM,EAAE,CAAC;KAC3B;IAMK,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAkBzD"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLMChain - Simple prompt chaining
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { getPricing, estimateTokens, calculateCost } from '../utils/pricing.js';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Prompt Template
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export class PromptTemplate {
|
|
10
|
+
template;
|
|
11
|
+
inputVariables;
|
|
12
|
+
constructor(template) {
|
|
13
|
+
this.template = template;
|
|
14
|
+
// Extract variables from {variable} patterns
|
|
15
|
+
const regex = /\{([^}]+)\}/g;
|
|
16
|
+
const matches = template.match(regex);
|
|
17
|
+
this.inputVariables = matches ? matches.map(m => m.slice(1, -1)) : [];
|
|
18
|
+
}
|
|
19
|
+
format(values) {
|
|
20
|
+
// Check for missing variables
|
|
21
|
+
const missing = this.inputVariables.filter(v => !(v in values));
|
|
22
|
+
if (missing.length > 0) {
|
|
23
|
+
throw new Error(`Missing required variables: ${missing.join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
let result = this.template;
|
|
26
|
+
for (const [key, value] of Object.entries(values)) {
|
|
27
|
+
result = result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
get inputVars() {
|
|
32
|
+
return this.inputVariables;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class LLMChain {
|
|
36
|
+
llm;
|
|
37
|
+
prompt;
|
|
38
|
+
outputKey;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.llm = options.llm;
|
|
41
|
+
this.prompt = options.prompt;
|
|
42
|
+
this.outputKey = options.outputKey ?? 'text';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Estimate cost before running
|
|
46
|
+
*/
|
|
47
|
+
estimateCost(inputs, model) {
|
|
48
|
+
const modelName = model ?? this.llm.defaultModel ?? 'default';
|
|
49
|
+
const formattedPrompt = this.prompt.format(inputs);
|
|
50
|
+
const estimatedTokensIn = estimateTokens(formattedPrompt);
|
|
51
|
+
const estimatedTokensOut = Math.max(1, Math.floor(estimatedTokensIn / 4));
|
|
52
|
+
const pricing = getPricing(modelName);
|
|
53
|
+
const estimatedCost = (estimatedTokensIn / 1_000_000 * pricing.input) +
|
|
54
|
+
(estimatedTokensOut / 1_000_000 * pricing.output);
|
|
55
|
+
// Rough latency: 100ms per 1K input + 50ms per 1K output
|
|
56
|
+
const estimatedLatency = Math.floor(estimatedTokensIn * 0.1 + estimatedTokensOut * 0.05);
|
|
57
|
+
return {
|
|
58
|
+
estimatedTokensIn,
|
|
59
|
+
estimatedTokensOut,
|
|
60
|
+
estimatedCostUsd: Math.round(estimatedCost * 1_000_000) / 1_000_000,
|
|
61
|
+
estimatedLatencyMs: estimatedLatency,
|
|
62
|
+
model: modelName,
|
|
63
|
+
pricing,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Invoke the chain synchronously
|
|
68
|
+
*/
|
|
69
|
+
async invoke(inputs) {
|
|
70
|
+
const formattedPrompt = this.prompt.format(inputs);
|
|
71
|
+
logger.debug(`[Chain] Prompt: ${formattedPrompt.slice(0, 100)}...`);
|
|
72
|
+
const messages = [{ role: 'user', content: formattedPrompt }];
|
|
73
|
+
const response = await this.llm.invoke(messages);
|
|
74
|
+
const outputs = {
|
|
75
|
+
[this.outputKey]: response.content,
|
|
76
|
+
};
|
|
77
|
+
// Include usage info if available
|
|
78
|
+
if (response.usage) {
|
|
79
|
+
outputs.usage = response.usage;
|
|
80
|
+
outputs.cost = calculateCost(response.model ?? 'default', response.usage.prompt_tokens, response.usage.completion_tokens);
|
|
81
|
+
}
|
|
82
|
+
return outputs;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Stream the response
|
|
86
|
+
*/
|
|
87
|
+
async *stream(inputs) {
|
|
88
|
+
const formattedPrompt = this.prompt.format(inputs);
|
|
89
|
+
logger.debug(`[Chain Stream] Prompt: ${formattedPrompt.slice(0, 100)}...`);
|
|
90
|
+
const messages = [{ role: 'user', content: formattedPrompt }];
|
|
91
|
+
for await (const chunk of this.llm.stream?.(messages) ?? []) {
|
|
92
|
+
yield chunk.delta;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Async invoke
|
|
97
|
+
*/
|
|
98
|
+
async ainvoke(inputs) {
|
|
99
|
+
return this.invoke(inputs);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Async stream
|
|
103
|
+
*/
|
|
104
|
+
async *astream(inputs) {
|
|
105
|
+
yield* this.stream(inputs);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Sequential Chain
|
|
110
|
+
// ============================================================================
|
|
111
|
+
export class SequentialChain {
|
|
112
|
+
chains;
|
|
113
|
+
inputVariables;
|
|
114
|
+
outputVariables;
|
|
115
|
+
constructor(options) {
|
|
116
|
+
this.chains = options.chains;
|
|
117
|
+
this.inputVariables = options.inputVariables;
|
|
118
|
+
this.outputVariables = options.outputVariables;
|
|
119
|
+
}
|
|
120
|
+
async invoke(inputs) {
|
|
121
|
+
let currentState = { ...inputs };
|
|
122
|
+
for (let i = 0; i < this.chains.length; i++) {
|
|
123
|
+
logger.debug(`[SequentialChain] Executing Chain ${i + 1}/${this.chains.length}`);
|
|
124
|
+
const chainOutput = await this.chains[i].invoke(currentState);
|
|
125
|
+
currentState = { ...currentState, ...chainOutput };
|
|
126
|
+
}
|
|
127
|
+
// Return only the requested output variables
|
|
128
|
+
const result = {};
|
|
129
|
+
for (const key of this.outputVariables) {
|
|
130
|
+
if (key in currentState) {
|
|
131
|
+
result[key] = currentState[key];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=llmchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llmchain.js","sourceRoot":"","sources":["../../src/chains/llmchain.ts"],"names":[],"mappings":"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"}
|