recursive-llm-ts 4.4.1 → 4.6.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 +375 -12
- package/bin/rlm-go +0 -0
- package/dist/bridge-interface.d.ts +19 -2
- package/dist/cache.d.ts +78 -0
- package/dist/cache.js +246 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +162 -0
- package/dist/errors.d.ts +113 -0
- package/dist/errors.js +219 -0
- package/dist/events.d.ts +126 -0
- package/dist/events.js +77 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +38 -1
- package/dist/retry.d.ts +56 -0
- package/dist/retry.js +185 -0
- package/dist/rlm.d.ts +391 -13
- package/dist/rlm.js +815 -182
- package/dist/streaming.d.ts +96 -0
- package/dist/streaming.js +210 -0
- package/go/README.md +9 -1
- package/go/rlm/context_overflow.go +566 -0
- package/go/rlm/context_overflow_test.go +783 -0
- package/go/rlm/errors.go +161 -1
- package/go/rlm/rlm.go +10 -0
- package/go/rlm/structured.go +53 -0
- package/go/rlm/textrank.go +273 -0
- package/go/rlm/textrank_test.go +335 -0
- package/go/rlm/tfidf.go +225 -0
- package/go/rlm/tfidf_test.go +272 -0
- package/go/rlm/types.go +25 -2
- package/package.json +16 -4
package/README.md
CHANGED
|
@@ -6,16 +6,33 @@ TypeScript/JavaScript package for [Recursive Language Models (RLM)](https://gith
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
**Core**
|
|
10
|
+
- **Unbounded Context** - Process 10M+ tokens without degradation via recursive decomposition
|
|
11
|
+
- **Structured Outputs** - Extract typed data with Zod schemas, parallel execution, and instructor-style retry
|
|
12
|
+
- **Streaming** - Progressive text output and partial structured objects via async iterables
|
|
13
|
+
- **Batch Operations** - Process multiple queries in parallel with concurrency control
|
|
14
|
+
|
|
15
|
+
**Performance & Resilience**
|
|
16
|
+
- **Pure Go Backend** - 50x faster startup, 3x less memory vs Python
|
|
17
|
+
- **Context Overflow Recovery** - Automatic detection and 6 reduction strategies (mapreduce, truncate, chunked, tfidf, textrank, refine)
|
|
18
|
+
- **Caching** - Exact-match caching with in-memory and file-based backends
|
|
19
|
+
- **Retry & Fallback** - Exponential backoff, jitter, and multi-provider fallback chains
|
|
20
|
+
- **AbortController** - Cancel any operation mid-flight
|
|
21
|
+
|
|
22
|
+
**Developer Experience**
|
|
23
|
+
- **Typed Errors** - Rich error hierarchy with codes, retryable flags, and suggestions
|
|
24
|
+
- **Event System** - Monitor LLM calls, cache hits, retries, and errors in real-time
|
|
25
|
+
- **Builder API** - Fluent configuration with full IDE discoverability
|
|
26
|
+
- **Factory Methods** - `RLM.fromEnv()`, `RLM.withDebug()`, `RLM.forAzure()`
|
|
27
|
+
- **Config Validation** - Catches typos and invalid settings at construction time
|
|
28
|
+
- **Result Formatters** - `prettyStats()`, `toJSON()`, `toMarkdown()`
|
|
29
|
+
|
|
30
|
+
**Ecosystem**
|
|
31
|
+
- **Provider Agnostic** - Works with OpenAI, Anthropic, Azure, Bedrock, local models
|
|
32
|
+
- **Meta-Agent Mode** - Automatically optimize queries for better results
|
|
33
|
+
- **Observability** - OpenTelemetry tracing, Langfuse integration, and debug logging
|
|
34
|
+
- **File Storage** - Process local directories or S3/MinIO/LocalStack buckets as LLM context
|
|
35
|
+
- **150+ Tests** - Comprehensive Vitest + Go test suites
|
|
19
36
|
|
|
20
37
|
## Installation
|
|
21
38
|
|
|
@@ -131,6 +148,236 @@ const result = await rlm.structuredCompletion(
|
|
|
131
148
|
);
|
|
132
149
|
```
|
|
133
150
|
|
|
151
|
+
### Streaming
|
|
152
|
+
|
|
153
|
+
Get progressive output with async iterables and AbortController support:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Stream text output
|
|
157
|
+
const stream = rlm.streamCompletion('Summarize', longDocument);
|
|
158
|
+
for await (const chunk of stream) {
|
|
159
|
+
if (chunk.type === 'text') process.stdout.write(chunk.text);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Collect all text
|
|
163
|
+
const text = await rlm.streamCompletion('Summarize', doc).toText();
|
|
164
|
+
|
|
165
|
+
// Cancel mid-stream
|
|
166
|
+
const controller = new AbortController();
|
|
167
|
+
const stream = rlm.streamCompletion('Summarize', doc, { signal: controller.signal });
|
|
168
|
+
setTimeout(() => controller.abort(), 5000);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Caching
|
|
172
|
+
|
|
173
|
+
Avoid redundant API calls with exact-match caching:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const rlm = new RLM('gpt-4o-mini', {
|
|
177
|
+
api_key: process.env.OPENAI_API_KEY,
|
|
178
|
+
cache: {
|
|
179
|
+
enabled: true,
|
|
180
|
+
strategy: 'exact', // 'exact' | 'none'
|
|
181
|
+
maxEntries: 1000,
|
|
182
|
+
ttl: 3600, // seconds
|
|
183
|
+
storage: 'memory', // 'memory' | 'file'
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const r1 = await rlm.completion('Summarize', doc); // API call
|
|
188
|
+
const r2 = await rlm.completion('Summarize', doc); // Cache hit!
|
|
189
|
+
console.log(r2.cached); // true
|
|
190
|
+
console.log(rlm.getCacheStats()); // { hits: 1, misses: 1, hitRate: 0.5, ... }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Retry & Resilience
|
|
194
|
+
|
|
195
|
+
Automatic retry with exponential backoff and provider fallback:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const rlm = new RLM('gpt-4o-mini', {
|
|
199
|
+
api_key: process.env.OPENAI_API_KEY,
|
|
200
|
+
retry: {
|
|
201
|
+
maxRetries: 3,
|
|
202
|
+
backoff: 'exponential', // 1s, 2s, 4s with jitter
|
|
203
|
+
onRetry: (attempt, error, delay) => {
|
|
204
|
+
console.log(`Retry ${attempt} after ${delay}ms: ${error.message}`);
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Or use standalone retry/fallback utilities:
|
|
210
|
+
import { withRetry, withFallback } from 'recursive-llm-ts';
|
|
211
|
+
|
|
212
|
+
const result = await withFallback(
|
|
213
|
+
(model) => rlm.completion(query, context),
|
|
214
|
+
{ models: ['gpt-4o', 'claude-sonnet-4-20250514', 'gemini-2.0-flash'] }
|
|
215
|
+
);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Event System
|
|
219
|
+
|
|
220
|
+
Monitor operations in real-time:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
const rlm = new RLM('gpt-4o-mini', { api_key: process.env.OPENAI_API_KEY });
|
|
224
|
+
|
|
225
|
+
rlm.on('llm_call', (e) => console.log(`Calling ${e.model}...`));
|
|
226
|
+
rlm.on('llm_response', (e) => console.log(`Response in ${e.duration}ms`));
|
|
227
|
+
rlm.on('cache', (e) => console.log(`Cache ${e.action}`));
|
|
228
|
+
rlm.on('error', (e) => reportToSentry(e.error));
|
|
229
|
+
rlm.on('completion_start', (e) => showSpinner());
|
|
230
|
+
rlm.on('completion_end', (e) => hideSpinner());
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Builder API
|
|
234
|
+
|
|
235
|
+
Fluent configuration with full IDE discoverability:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
const rlm = RLM.builder('gpt-4o-mini')
|
|
239
|
+
.apiKey(process.env.OPENAI_API_KEY!)
|
|
240
|
+
.maxDepth(10)
|
|
241
|
+
.maxIterations(30)
|
|
242
|
+
.withMetaAgent({ model: 'gpt-4o' })
|
|
243
|
+
.withDebug()
|
|
244
|
+
.withCache({ strategy: 'exact' })
|
|
245
|
+
.withRetry({ maxRetries: 3 })
|
|
246
|
+
.withFallback(['gpt-4o', 'claude-sonnet-4-20250514'])
|
|
247
|
+
.build();
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Factory Methods
|
|
251
|
+
|
|
252
|
+
Quick setup for common configurations:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// From environment variables
|
|
256
|
+
const rlm = RLM.fromEnv('gpt-4o-mini');
|
|
257
|
+
|
|
258
|
+
// Debug mode
|
|
259
|
+
const rlm = RLM.withDebug('gpt-4o-mini');
|
|
260
|
+
|
|
261
|
+
// Azure OpenAI
|
|
262
|
+
const rlm = RLM.forAzure('my-deployment', {
|
|
263
|
+
apiBase: 'https://myresource.openai.azure.com',
|
|
264
|
+
apiVersion: '2024-02-15-preview',
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Batch Operations
|
|
269
|
+
|
|
270
|
+
Process multiple queries in parallel:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
const results = await rlm.batchCompletion([
|
|
274
|
+
{ query: 'Summarize chapter 1', context: ch1 },
|
|
275
|
+
{ query: 'Summarize chapter 2', context: ch2 },
|
|
276
|
+
{ query: 'Summarize chapter 3', context: ch3 },
|
|
277
|
+
], { concurrency: 2 });
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Error Handling
|
|
281
|
+
|
|
282
|
+
Rich error hierarchy with actionable information:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import {
|
|
286
|
+
RLMRateLimitError, RLMValidationError,
|
|
287
|
+
RLMTimeoutError, RLMContextOverflowError
|
|
288
|
+
} from 'recursive-llm-ts';
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
const result = await rlm.completion(query, context);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
if (err instanceof RLMContextOverflowError) {
|
|
294
|
+
console.log(`Context overflow: ${err.requestTokens} tokens > ${err.modelLimit} limit`);
|
|
295
|
+
// Enable context_overflow config to auto-recover from this
|
|
296
|
+
} else if (err instanceof RLMRateLimitError) {
|
|
297
|
+
console.log(`Rate limited. Retry after: ${err.retryAfter}s`);
|
|
298
|
+
} else if (err instanceof RLMValidationError) {
|
|
299
|
+
console.log(`Schema mismatch:`, err.zodErrors);
|
|
300
|
+
} else if (err instanceof RLMTimeoutError) {
|
|
301
|
+
console.log(`Timed out after ${err.elapsed}ms`);
|
|
302
|
+
}
|
|
303
|
+
// All RLM errors have: err.code, err.retryable, err.suggestion
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Context Overflow Handling
|
|
308
|
+
|
|
309
|
+
Automatically detect and recover from context window overflows. When your input exceeds the model's token limit, RLM catches the error and applies a reduction strategy to fit the context within bounds.
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
const rlm = new RLM('gpt-4o-mini', {
|
|
313
|
+
api_key: process.env.OPENAI_API_KEY,
|
|
314
|
+
context_overflow: {
|
|
315
|
+
enabled: true, // Enable overflow recovery (default: true)
|
|
316
|
+
strategy: 'tfidf', // Reduction strategy (see table below)
|
|
317
|
+
max_model_tokens: 32768, // Override auto-detected limit (optional)
|
|
318
|
+
safety_margin: 0.15, // Reserve 15% for prompts/overhead (default: 0.15)
|
|
319
|
+
max_reduction_attempts: 3, // Max retry attempts (default: 3)
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Process a document that may exceed the model's context window
|
|
324
|
+
const result = await rlm.completion(
|
|
325
|
+
'Summarize the key findings',
|
|
326
|
+
veryLargeDocument // If too large, auto-reduces and retries
|
|
327
|
+
);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Builder API:**
|
|
331
|
+
```typescript
|
|
332
|
+
const rlm = RLM.builder('gpt-4o-mini')
|
|
333
|
+
.apiKey(process.env.OPENAI_API_KEY!)
|
|
334
|
+
.withContextOverflow({ strategy: 'textrank', max_model_tokens: 32768 })
|
|
335
|
+
.build();
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Strategy Comparison:**
|
|
339
|
+
|
|
340
|
+
| Strategy | API Calls | Speed | Quality | Best For |
|
|
341
|
+
|----------|-----------|-------|---------|----------|
|
|
342
|
+
| `mapreduce` | Many (parallel) | Medium | High | General-purpose, large documents |
|
|
343
|
+
| `truncate` | 0 | Fastest | Low | Quick-and-dirty, when beginning of doc matters |
|
|
344
|
+
| `chunked` | Many (sequential) | Slow | High | Detailed extraction from specific sections |
|
|
345
|
+
| `tfidf` | 0 | Fast | Medium | Fast first pass, keyword-rich documents |
|
|
346
|
+
| `textrank` | 0 | Fast | Medium-High | Documents with clear sentence structure |
|
|
347
|
+
| `refine` | Many (sequential) | Slow | Highest | When quality matters most, iterative refinement |
|
|
348
|
+
|
|
349
|
+
**Strategy Details:**
|
|
350
|
+
|
|
351
|
+
- **`mapreduce`** (default) - Splits context into chunks, summarizes each in parallel via LLM calls, then merges summaries. Good balance of quality and speed.
|
|
352
|
+
- **`truncate`** - Drops tokens from the end to fit the budget. Zero API calls, but loses information. Best when the beginning of the document is most important.
|
|
353
|
+
- **`chunked`** - Processes chunks sequentially, extracting relevant content from each. Higher quality than mapreduce for targeted extraction.
|
|
354
|
+
- **`tfidf`** - Pure Go, zero API calls. Uses TF-IDF scoring to select the most informative sentences. Preserves original document order. Great for a fast, no-cost first pass.
|
|
355
|
+
- **`textrank`** - Pure Go, zero API calls. Graph-based sentence ranking using PageRank over cosine-similarity of TF-IDF vectors. Better at identifying structurally important sentences than plain TF-IDF.
|
|
356
|
+
- **`refine`** - Sequential iterative refinement. Processes chunks one at a time, building and refining an answer progressively. Highest quality but slowest, as each chunk sees the accumulated context.
|
|
357
|
+
|
|
358
|
+
### Config Validation
|
|
359
|
+
|
|
360
|
+
Catch configuration issues at construction time:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
const rlm = new RLM('gpt-4o-mini', { max_detph: 5 }); // typo!
|
|
364
|
+
const result = rlm.validate();
|
|
365
|
+
// result.issues: [{ level: 'warning', field: 'max_detph', message: 'Unknown config key...' }]
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Result Formatting
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const result = await rlm.completion(query, context);
|
|
372
|
+
const formatted = rlm.formatResult(result);
|
|
373
|
+
|
|
374
|
+
console.log(formatted.prettyStats());
|
|
375
|
+
// "LLM Calls: 3 | Iterations: 12 | Depth: 2"
|
|
376
|
+
|
|
377
|
+
console.log(formatted.toMarkdown());
|
|
378
|
+
// Full markdown-formatted result with stats table
|
|
379
|
+
```
|
|
380
|
+
|
|
134
381
|
### Agent Coordinator (Advanced)
|
|
135
382
|
|
|
136
383
|
For complex multi-field schemas, use the coordinator API:
|
|
@@ -463,6 +710,42 @@ Process a query using files from local or S3 storage as context.
|
|
|
463
710
|
|
|
464
711
|
Extract structured data from file-based context.
|
|
465
712
|
|
|
713
|
+
#### `streamCompletion(query, context, options?): RLMStream`
|
|
714
|
+
|
|
715
|
+
Stream a completion with progressive text output. Returns an async iterable.
|
|
716
|
+
|
|
717
|
+
#### `streamStructuredCompletion<T>(query, context, schema, options?): RLMStream<T>`
|
|
718
|
+
|
|
719
|
+
Stream a structured completion with partial object updates.
|
|
720
|
+
|
|
721
|
+
#### `batchCompletion(queries, options?): Promise<Array<RLMCompletionResult | Error>>`
|
|
722
|
+
|
|
723
|
+
Execute multiple completions in parallel with concurrency control.
|
|
724
|
+
|
|
725
|
+
#### `batchStructuredCompletion<T>(queries, options?): Promise<Array<StructuredRLMResult<T> | Error>>`
|
|
726
|
+
|
|
727
|
+
Execute multiple structured completions in parallel.
|
|
728
|
+
|
|
729
|
+
#### `validate(): ValidationResult`
|
|
730
|
+
|
|
731
|
+
Validate the current configuration without making API calls.
|
|
732
|
+
|
|
733
|
+
#### `getCacheStats(): CacheStats`
|
|
734
|
+
|
|
735
|
+
Get cache performance statistics (hits, misses, hit rate).
|
|
736
|
+
|
|
737
|
+
#### `clearCache(): void`
|
|
738
|
+
|
|
739
|
+
Clear the completion cache.
|
|
740
|
+
|
|
741
|
+
#### `formatResult(result): RLMResultFormatter`
|
|
742
|
+
|
|
743
|
+
Create a formatted result with `prettyStats()`, `toJSON()`, `toMarkdown()`.
|
|
744
|
+
|
|
745
|
+
#### `on(event, listener) / off(event, listener) / once(event, listener)`
|
|
746
|
+
|
|
747
|
+
Register/remove event listeners. Events: `llm_call`, `llm_response`, `error`, `cache`, `completion_start`, `completion_end`, `retry`, `validation_retry`, `meta_agent`, `recursion`.
|
|
748
|
+
|
|
466
749
|
#### `cleanup(): Promise<void>`
|
|
467
750
|
|
|
468
751
|
Clean up the bridge and free resources.
|
|
@@ -508,12 +791,50 @@ interface RLMConfig {
|
|
|
508
791
|
// Shorthand for observability.debug
|
|
509
792
|
debug?: boolean;
|
|
510
793
|
|
|
511
|
-
// LiteLLM parameters
|
|
794
|
+
// LiteLLM parameters
|
|
512
795
|
api_version?: string; // API version (e.g., for Azure)
|
|
513
796
|
timeout?: number; // Request timeout in seconds
|
|
514
797
|
temperature?: number; // Sampling temperature
|
|
515
798
|
max_tokens?: number; // Maximum tokens in response
|
|
516
|
-
|
|
799
|
+
|
|
800
|
+
// Context overflow recovery
|
|
801
|
+
context_overflow?: ContextOverflowConfig;
|
|
802
|
+
|
|
803
|
+
// Caching, retry, fallback
|
|
804
|
+
cache?: CacheConfig; // Cache configuration
|
|
805
|
+
retry?: RetryConfig; // Retry configuration
|
|
806
|
+
fallback?: FallbackConfig; // Fallback model configuration
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
interface CacheConfig {
|
|
810
|
+
enabled?: boolean; // Enable caching (default: false)
|
|
811
|
+
strategy?: 'exact' | 'none'; // Cache strategy (default: 'exact')
|
|
812
|
+
maxEntries?: number; // Max cached entries (default: 1000)
|
|
813
|
+
ttl?: number; // Time-to-live in seconds (default: 3600)
|
|
814
|
+
storage?: 'memory' | 'file'; // Storage backend (default: 'memory')
|
|
815
|
+
cacheDir?: string; // Dir for file cache (default: '.rlm-cache')
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
interface RetryConfig {
|
|
819
|
+
maxRetries?: number; // Max retries (default: 3)
|
|
820
|
+
backoff?: 'exponential' | 'linear' | 'fixed';
|
|
821
|
+
baseDelay?: number; // Base delay ms (default: 1000)
|
|
822
|
+
maxDelay?: number; // Max delay ms (default: 30000)
|
|
823
|
+
jitter?: boolean; // Add jitter (default: true)
|
|
824
|
+
onRetry?: (attempt: number, error: Error, delay: number) => void;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
interface FallbackConfig {
|
|
828
|
+
models?: string[]; // Ordered fallback models
|
|
829
|
+
strategy?: 'sequential'; // Fallback strategy
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
interface ContextOverflowConfig {
|
|
833
|
+
enabled?: boolean; // Enable overflow recovery (default: true)
|
|
834
|
+
max_model_tokens?: number; // Override auto-detected model limit (0 = auto-detect)
|
|
835
|
+
strategy?: 'mapreduce' | 'truncate' | 'chunked' | 'tfidf' | 'textrank' | 'refine';
|
|
836
|
+
safety_margin?: number; // Fraction to reserve for overhead (default: 0.15)
|
|
837
|
+
max_reduction_attempts?: number; // Max reduction retries (default: 3)
|
|
517
838
|
}
|
|
518
839
|
|
|
519
840
|
interface MetaAgentConfig {
|
|
@@ -583,6 +904,22 @@ interface FileStorageResult {
|
|
|
583
904
|
totalSize: number;
|
|
584
905
|
skipped: Array<{ relativePath: string; reason: string }>;
|
|
585
906
|
}
|
|
907
|
+
|
|
908
|
+
// Error hierarchy - all extend RLMError
|
|
909
|
+
class RLMError extends Error {
|
|
910
|
+
code: string; // Machine-readable: "RATE_LIMIT", "VALIDATION", etc.
|
|
911
|
+
retryable: boolean; // Whether caller should retry
|
|
912
|
+
suggestion?: string; // Human-readable fix suggestion
|
|
913
|
+
}
|
|
914
|
+
class RLMValidationError extends RLMError { expected; received; zodErrors; }
|
|
915
|
+
class RLMRateLimitError extends RLMError { retryAfter?: number; }
|
|
916
|
+
class RLMTimeoutError extends RLMError { elapsed; limit; }
|
|
917
|
+
class RLMProviderError extends RLMError { statusCode; provider; }
|
|
918
|
+
class RLMBinaryError extends RLMError { binaryPath; }
|
|
919
|
+
class RLMConfigError extends RLMError { field; value; }
|
|
920
|
+
class RLMContextOverflowError extends RLMError { modelLimit; requestTokens; }
|
|
921
|
+
class RLMSchemaError extends RLMError { path; constraint; }
|
|
922
|
+
class RLMAbortError extends RLMError {}
|
|
586
923
|
```
|
|
587
924
|
|
|
588
925
|
## Environment Variables
|
|
@@ -882,6 +1219,32 @@ The recursive-llm approach breaks down large contexts into manageable chunks and
|
|
|
882
1219
|
- ✅ **Type-safe** - Full TypeScript type definitions
|
|
883
1220
|
- ✅ **Simple API** - Just `npm install` and start using
|
|
884
1221
|
|
|
1222
|
+
## Testing
|
|
1223
|
+
|
|
1224
|
+
```bash
|
|
1225
|
+
# Run all tests (Vitest)
|
|
1226
|
+
npm test
|
|
1227
|
+
|
|
1228
|
+
# Watch mode
|
|
1229
|
+
npm run test:watch
|
|
1230
|
+
|
|
1231
|
+
# Coverage
|
|
1232
|
+
npm run test:coverage
|
|
1233
|
+
|
|
1234
|
+
# Type-check
|
|
1235
|
+
npm run typecheck
|
|
1236
|
+
|
|
1237
|
+
# Go tests
|
|
1238
|
+
cd go && go test ./rlm/... -v
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
## Documentation
|
|
1242
|
+
|
|
1243
|
+
- [Quick Start Guide](docs/QUICKSTART.md)
|
|
1244
|
+
- [Architecture Overview](docs/ARCHITECTURE.md)
|
|
1245
|
+
- [Contributing Guide](CONTRIBUTING.md)
|
|
1246
|
+
- [UX/DX Gap Analysis](docs/UX-DX-GAP-ANALYSIS.md)
|
|
1247
|
+
|
|
885
1248
|
## Publishing
|
|
886
1249
|
|
|
887
1250
|
This package uses automated GitHub Actions workflows to publish to npm. See [RELEASE.md](RELEASE.md) for detailed instructions on publishing new versions.
|
package/bin/rlm-go
CHANGED
|
Binary file
|
|
@@ -5,7 +5,7 @@ export interface RLMStats {
|
|
|
5
5
|
parsing_retries?: number;
|
|
6
6
|
}
|
|
7
7
|
export interface RLMResult {
|
|
8
|
-
result: string
|
|
8
|
+
result: string;
|
|
9
9
|
stats: RLMStats;
|
|
10
10
|
structured_result?: boolean;
|
|
11
11
|
trace_events?: TraceEvent[];
|
|
@@ -36,6 +36,18 @@ export interface TraceEvent {
|
|
|
36
36
|
span_id?: string;
|
|
37
37
|
parent_id?: string;
|
|
38
38
|
}
|
|
39
|
+
export interface ContextOverflowConfig {
|
|
40
|
+
/** Enable automatic context overflow recovery (default: true) */
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
/** Override detected model token limit (0 = auto-detect from API errors) */
|
|
43
|
+
max_model_tokens?: number;
|
|
44
|
+
/** Strategy: 'mapreduce' (default), 'truncate', 'chunked', 'tfidf', 'textrank', or 'refine' */
|
|
45
|
+
strategy?: 'mapreduce' | 'truncate' | 'chunked' | 'tfidf' | 'textrank' | 'refine';
|
|
46
|
+
/** Fraction of token budget to reserve for prompts/overhead (default: 0.15) */
|
|
47
|
+
safety_margin?: number;
|
|
48
|
+
/** Maximum reduction attempts before giving up (default: 3) */
|
|
49
|
+
max_reduction_attempts?: number;
|
|
50
|
+
}
|
|
39
51
|
export interface RLMConfig {
|
|
40
52
|
recursive_model?: string;
|
|
41
53
|
api_base?: string;
|
|
@@ -46,8 +58,13 @@ export interface RLMConfig {
|
|
|
46
58
|
go_binary_path?: string;
|
|
47
59
|
meta_agent?: MetaAgentConfig;
|
|
48
60
|
observability?: ObservabilityConfig;
|
|
61
|
+
context_overflow?: ContextOverflowConfig;
|
|
49
62
|
debug?: boolean;
|
|
50
|
-
|
|
63
|
+
api_version?: string;
|
|
64
|
+
timeout?: number;
|
|
65
|
+
temperature?: number;
|
|
66
|
+
max_tokens?: number;
|
|
67
|
+
structured?: any;
|
|
51
68
|
}
|
|
52
69
|
export interface FileStorageConfig {
|
|
53
70
|
/** Storage type: 'local' or 's3' */
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caching layer for recursive-llm-ts completions.
|
|
3
|
+
*
|
|
4
|
+
* Provides exact-match caching to avoid redundant API calls for
|
|
5
|
+
* identical query+context pairs. Supports in-memory and file-based storage.
|
|
6
|
+
*/
|
|
7
|
+
export interface CacheConfig {
|
|
8
|
+
/** Enable/disable caching (default: false) */
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
/** Cache strategy (default: 'exact') */
|
|
11
|
+
strategy?: 'exact' | 'none';
|
|
12
|
+
/** Maximum number of cached entries (default: 1000) */
|
|
13
|
+
maxEntries?: number;
|
|
14
|
+
/** Time-to-live in seconds (default: 3600 = 1 hour) */
|
|
15
|
+
ttl?: number;
|
|
16
|
+
/** Storage backend (default: 'memory') */
|
|
17
|
+
storage?: 'memory' | 'file';
|
|
18
|
+
/** Directory for file-based cache (default: .rlm-cache) */
|
|
19
|
+
cacheDir?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CacheStats {
|
|
22
|
+
hits: number;
|
|
23
|
+
misses: number;
|
|
24
|
+
size: number;
|
|
25
|
+
hitRate: number;
|
|
26
|
+
evictions: number;
|
|
27
|
+
}
|
|
28
|
+
export interface CacheProvider {
|
|
29
|
+
get<T>(key: string): T | undefined;
|
|
30
|
+
set<T>(key: string, value: T, ttl: number): void;
|
|
31
|
+
has(key: string): boolean;
|
|
32
|
+
delete(key: string): boolean;
|
|
33
|
+
clear(): void;
|
|
34
|
+
size(): number;
|
|
35
|
+
}
|
|
36
|
+
export declare class MemoryCache implements CacheProvider {
|
|
37
|
+
private store;
|
|
38
|
+
private maxEntries;
|
|
39
|
+
constructor(maxEntries?: number);
|
|
40
|
+
get<T>(key: string): T | undefined;
|
|
41
|
+
set<T>(key: string, value: T, ttl: number): void;
|
|
42
|
+
has(key: string): boolean;
|
|
43
|
+
delete(key: string): boolean;
|
|
44
|
+
clear(): void;
|
|
45
|
+
size(): number;
|
|
46
|
+
}
|
|
47
|
+
export declare class FileCache implements CacheProvider {
|
|
48
|
+
private cacheDir;
|
|
49
|
+
private maxEntries;
|
|
50
|
+
constructor(cacheDir?: string, maxEntries?: number);
|
|
51
|
+
private filePath;
|
|
52
|
+
get<T>(key: string): T | undefined;
|
|
53
|
+
set<T>(key: string, value: T, ttl: number): void;
|
|
54
|
+
has(key: string): boolean;
|
|
55
|
+
delete(key: string): boolean;
|
|
56
|
+
clear(): void;
|
|
57
|
+
size(): number;
|
|
58
|
+
}
|
|
59
|
+
export declare class RLMCache {
|
|
60
|
+
private provider;
|
|
61
|
+
private config;
|
|
62
|
+
private stats;
|
|
63
|
+
constructor(config?: CacheConfig);
|
|
64
|
+
/** Check if caching is enabled */
|
|
65
|
+
get enabled(): boolean;
|
|
66
|
+
/** Look up a cached result */
|
|
67
|
+
lookup<T>(model: string, query: string, context: string, extra?: Record<string, unknown>): {
|
|
68
|
+
hit: boolean;
|
|
69
|
+
value?: T;
|
|
70
|
+
};
|
|
71
|
+
/** Store a result in the cache */
|
|
72
|
+
store<T>(model: string, query: string, context: string, value: T, extra?: Record<string, unknown>): void;
|
|
73
|
+
/** Get cache statistics */
|
|
74
|
+
getStats(): CacheStats;
|
|
75
|
+
/** Clear the cache */
|
|
76
|
+
clear(): void;
|
|
77
|
+
private updateHitRate;
|
|
78
|
+
}
|