@elizaos/plugin-rlm 2.0.0-alpha.7 → 2.0.0-beta.1
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 +211 -0
- package/dist/index.js +104 -8
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# plugin-rlm
|
|
2
|
+
|
|
3
|
+
RLM (Recursive Language Model) plugin for elizaOS.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This plugin integrates **Recursive Language Models (RLMs)** into elizaOS, enabling LLMs to process arbitrarily long contexts through recursive self-calls in a REPL environment.
|
|
8
|
+
|
|
9
|
+
RLMs represent a breakthrough in long-context processing that:
|
|
10
|
+
- Handles inputs **up to 2 orders of magnitude beyond** standard model context windows
|
|
11
|
+
- Outperforms vanilla GPT-5 on long-context benchmarks using smaller models
|
|
12
|
+
- Uses strategies like **Peeking**, **Grepping**, **Partition+Map**, and **Summarization**
|
|
13
|
+
|
|
14
|
+
### Reference
|
|
15
|
+
|
|
16
|
+
- **Paper**: [Recursive Language Models](https://arxiv.org/abs/2512.24601) (arXiv:2512.24601)
|
|
17
|
+
- **Authors**: Alex L. Zhang, Tim Kraska, Omar Khattab (MIT CSAIL)
|
|
18
|
+
- **Official Implementation**: [github.com/alexzhang13/rlm](https://github.com/alexzhang13/rlm)
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
# Optional: Install RLM backend
|
|
22
|
+
pip install git+https://github.com/alexzhang13/rlm.git
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### TypeScript
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd plugins/plugin-rlm
|
|
29
|
+
npm install
|
|
30
|
+
npm run build
|
|
31
|
+
```
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
The plugin reads configuration from environment variables:
|
|
35
|
+
|
|
36
|
+
| Variable | Default | Description |
|
|
37
|
+
|----------|---------|-------------|
|
|
38
|
+
| `ELIZA_RLM_BACKEND` | `gemini` | LLM backend (`openai`, `anthropic`, `gemini`, `groq`, `openrouter`) |
|
|
39
|
+
| `ELIZA_RLM_ENV` | `local` | Execution environment (`local`, `docker`, `modal`, `prime`) |
|
|
40
|
+
| `ELIZA_RLM_MAX_ITERATIONS` | `4` | Maximum REPL iterations |
|
|
41
|
+
| `ELIZA_RLM_MAX_DEPTH` | `1` | Maximum recursion depth |
|
|
42
|
+
| `ELIZA_RLM_VERBOSE` | `false` | Enable verbose logging |
|
|
43
|
+
| `ELIZA_RLM_PYTHON_PATH` | `python` | Python executable path (TypeScript/Rust IPC) |
|
|
44
|
+
| `ELIZA_RLM_MAX_RETRIES` | `3` | Maximum retry attempts for transient failures |
|
|
45
|
+
| `ELIZA_RLM_RETRY_DELAY` | `1000` | Base delay (ms) between retries |
|
|
46
|
+
| `ELIZA_RLM_RETRY_MAX_DELAY` | `30000` | Maximum delay (ms) between retries |
|
|
47
|
+
|
|
48
|
+
### Retry Logic
|
|
49
|
+
|
|
50
|
+
The plugin includes automatic retry with exponential backoff for transient failures. Retries are triggered for:
|
|
51
|
+
- Connection timeouts
|
|
52
|
+
- Rate limit errors (429)
|
|
53
|
+
- Temporary server errors (503)
|
|
54
|
+
- Network connection failures
|
|
55
|
+
|
|
56
|
+
**Assumptions and Limitations:**
|
|
57
|
+
- Retry detection uses substring matching on error messages (e.g., "timeout", "connection", "rate limit")
|
|
58
|
+
- Different LLM backends may use different error message formats
|
|
59
|
+
- Non-transient errors (e.g., authentication, validation) are NOT retried
|
|
60
|
+
|
|
61
|
+
### Metrics (TypeScript)
|
|
62
|
+
|
|
63
|
+
The TypeScript client provides metrics for monitoring:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const client = new RLMClient();
|
|
67
|
+
|
|
68
|
+
// Get current metrics
|
|
69
|
+
const metrics = client.getMetrics();
|
|
70
|
+
console.log(metrics.totalRequests, metrics.successfulRequests);
|
|
71
|
+
|
|
72
|
+
// Register callback for real-time metrics
|
|
73
|
+
client.onMetrics((metrics) => {
|
|
74
|
+
// Send to Prometheus, Datadog, etc.
|
|
75
|
+
exporter.recordGauge('rlm_latency_p95', metrics.p95LatencyMs);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Available metrics:
|
|
80
|
+
- `totalRequests`, `successfulRequests`, `failedRequests`, `stubResponses`
|
|
81
|
+
- `totalRetries` - total retry attempts across all requests
|
|
82
|
+
- `averageLatencyMs`, `p95LatencyMs` - latency percentiles (rolling 1000 samples)
|
|
83
|
+
- `lastRequestTimestamp`, `lastErrorTimestamp`, `lastError`
|
|
84
|
+
|
|
85
|
+
### Backend API Keys
|
|
86
|
+
|
|
87
|
+
Depending on your chosen backend, set the appropriate API key:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# For OpenAI backend
|
|
91
|
+
export OPENAI_API_KEY=sk-...
|
|
92
|
+
|
|
93
|
+
# For Anthropic backend
|
|
94
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
95
|
+
|
|
96
|
+
# For Google Gemini backend
|
|
97
|
+
export GEMINI_API_KEY=...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Usage
|
|
101
|
+
# The plugin is auto-loaded by elizaOS runtime
|
|
102
|
+
# Or use the client directly:
|
|
103
|
+
client = RLMClient()
|
|
104
|
+
result = await client.infer("Process this very long text...")
|
|
105
|
+
print(result.text)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### TypeScript
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { rlmPlugin, RLMClient } from "@elizaos/plugin-rlm";
|
|
112
|
+
|
|
113
|
+
// Plugin is auto-registered when loaded
|
|
114
|
+
// Or use client directly:
|
|
115
|
+
const client = new RLMClient();
|
|
116
|
+
const result = await client.infer("Process this very long text...");
|
|
117
|
+
console.log(result.text);
|
|
118
|
+
```
|
|
119
|
+
## Model Types
|
|
120
|
+
|
|
121
|
+
The plugin registers handlers for the following model types:
|
|
122
|
+
|
|
123
|
+
| Model Type | Description |
|
|
124
|
+
|------------|-------------|
|
|
125
|
+
| `TEXT_SMALL` | Small text generation |
|
|
126
|
+
| `TEXT_LARGE` | Large text generation |
|
|
127
|
+
| `TEXT_REASONING_SMALL` | Small reasoning model |
|
|
128
|
+
| `TEXT_REASONING_LARGE` | Large reasoning model |
|
|
129
|
+
| `TEXT_COMPLETION` | Text completion |
|
|
130
|
+
| `TEXT_RLM_LARGE` | Explicit RLM mode |
|
|
131
|
+
| `TEXT_RLM_REASONING` | Explicit RLM with reasoning |
|
|
132
|
+
|
|
133
|
+
## Architecture
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
plugins/plugin-rlm/
|
|
137
|
+
├── README.md # This file
|
|
138
|
+
└── typescript/
|
|
139
|
+
├── package.json
|
|
140
|
+
├── types.ts # TypeScript types
|
|
141
|
+
├── client.ts # RLMClient
|
|
142
|
+
├── index.ts # Plugin definition
|
|
143
|
+
└── __tests__/
|
|
144
|
+
├── plugin.test.ts # Unit tests
|
|
145
|
+
└── integration.test.ts # Integration tests
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Cross-Language Design
|
|
149
|
+
|
|
150
|
+
Since the official RLM library is Python-only:
|
|
151
|
+
|
|
152
|
+
1. **Python**: Direct integration with the `rlm` library
|
|
153
|
+
2. **TypeScript**: IPC via Python subprocess with JSON-RPC protocol
|
|
154
|
+
3. **Rust**: IPC via Python subprocess with JSON-RPC protocol
|
|
155
|
+
|
|
156
|
+
All implementations fall back to **stub mode** when the RLM backend is unavailable, returning safe placeholder responses without throwing errors.
|
|
157
|
+
|
|
158
|
+
## Stub Mode
|
|
159
|
+
|
|
160
|
+
When the RLM backend is not installed or unavailable, the plugin operates in stub mode:
|
|
161
|
+
|
|
162
|
+
This allows the plugin to be loaded and used without the RLM dependency for testing and development purposes.
|
|
163
|
+
|
|
164
|
+
## Testing
|
|
165
|
+
### TypeScript
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cd plugins/plugin-rlm
|
|
169
|
+
npm install
|
|
170
|
+
npm test
|
|
171
|
+
```
|
|
172
|
+
## How RLM Works
|
|
173
|
+
|
|
174
|
+
RLMs treat long prompts as external objects stored in a Python REPL environment. Instead of feeding the entire input to the model, the LM:
|
|
175
|
+
|
|
176
|
+
1. **Peeks** at portions of the context
|
|
177
|
+
2. **Greps** for relevant information using regex
|
|
178
|
+
3. **Partitions** the context into manageable chunks
|
|
179
|
+
4. **Maps** recursive LM calls over chunks
|
|
180
|
+
5. **Summarizes** and aggregates results
|
|
181
|
+
|
|
182
|
+
This approach addresses "context rot" - the degradation of model performance as prompt length increases.
|
|
183
|
+
|
|
184
|
+
### Example: Long Context Processing
|
|
185
|
+
|
|
186
|
+
## Performance
|
|
187
|
+
|
|
188
|
+
Based on the original paper's benchmarks:
|
|
189
|
+
|
|
190
|
+
| Benchmark | GPT-5 | RLM(GPT-5-mini) | Improvement |
|
|
191
|
+
|-----------|-------|-----------------|-------------|
|
|
192
|
+
| OOLONG (132k) | 30% | 64% | +114% |
|
|
193
|
+
| OOLONG (263k) | 31% | 46% | +49% |
|
|
194
|
+
| BrowseComp-Plus | ~60% | 100% | +67% |
|
|
195
|
+
|
|
196
|
+
RLM using GPT-5-mini **outperforms vanilla GPT-5** while being cheaper per query.
|
|
197
|
+
|
|
198
|
+
## Limitations
|
|
199
|
+
|
|
200
|
+
- **Latency**: RLM calls take longer due to recursive processing
|
|
201
|
+
- **Cost**: Multiple LLM calls may increase API costs
|
|
202
|
+
- **Python Dependency**: TypeScript and Rust rely on Python IPC
|
|
203
|
+
- **No Streaming**: Streaming is not yet supported in RLM
|
|
204
|
+
|
|
205
|
+
## Contributing
|
|
206
|
+
|
|
207
|
+
Contributions are welcome! Please see the main elizaOS repository for contribution guidelines.
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
// index.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
buildCanonicalSystemPrompt,
|
|
4
|
+
logger,
|
|
5
|
+
ModelType,
|
|
6
|
+
recordLlmCall,
|
|
7
|
+
resolveEffectiveSystemPrompt
|
|
8
|
+
} from "@elizaos/core";
|
|
3
9
|
|
|
4
10
|
// client.ts
|
|
5
11
|
import { spawn } from "child_process";
|
|
6
12
|
import * as path from "path";
|
|
7
13
|
import * as readline from "readline";
|
|
14
|
+
import { assertRecordedLlmCall } from "@elizaos/core";
|
|
8
15
|
|
|
9
16
|
// types.ts
|
|
10
17
|
var DEFAULT_CONFIG = {
|
|
@@ -221,7 +228,7 @@ var RLMClient = class _RLMClient {
|
|
|
221
228
|
this.pendingRequests.delete(response.id);
|
|
222
229
|
pending.resolve(response);
|
|
223
230
|
}
|
|
224
|
-
} catch (
|
|
231
|
+
} catch (_error) {
|
|
225
232
|
this.logger.error(`Failed to parse RLM server message: ${line}`);
|
|
226
233
|
}
|
|
227
234
|
}
|
|
@@ -295,6 +302,11 @@ var RLMClient = class _RLMClient {
|
|
|
295
302
|
return typeof messages === "string" ? [{ role: "user", content: messages }] : messages;
|
|
296
303
|
}
|
|
297
304
|
async infer(messages, opts) {
|
|
305
|
+
assertRecordedLlmCall({
|
|
306
|
+
actionType: "rlm.client.infer",
|
|
307
|
+
model: opts?.rootModel,
|
|
308
|
+
purpose: "external_llm"
|
|
309
|
+
});
|
|
298
310
|
const startTime = Date.now();
|
|
299
311
|
const { maxRetries = 3, retryBaseDelay = 1e3, retryMaxDelay = 3e4 } = this.config;
|
|
300
312
|
const RETRYABLE_PATTERNS = ["timeout", "rate limit", "connection", "503", "429", "econnreset"];
|
|
@@ -367,8 +379,71 @@ function stubResult(error) {
|
|
|
367
379
|
};
|
|
368
380
|
}
|
|
369
381
|
|
|
382
|
+
// cost.ts
|
|
383
|
+
var MODEL_PRICING = {
|
|
384
|
+
openai: {
|
|
385
|
+
"gpt-5": { input: 2.5, output: 10 },
|
|
386
|
+
"gpt-5-preview": { input: 10, output: 30 },
|
|
387
|
+
"gpt-5-mini": { input: 0.15, output: 0.6 },
|
|
388
|
+
"gpt-3.5-turbo": { input: 0.5, output: 1.5 }
|
|
389
|
+
},
|
|
390
|
+
anthropic: {
|
|
391
|
+
"claude-3-5-sonnet-20241022": { input: 3, output: 15 },
|
|
392
|
+
"claude-3-5-haiku-20241022": { input: 0.8, output: 4 },
|
|
393
|
+
"claude-3-opus-20240229": { input: 15, output: 75 },
|
|
394
|
+
"claude-3-sonnet-20240229": { input: 3, output: 15 },
|
|
395
|
+
"claude-3-haiku-20240307": { input: 0.25, output: 1.25 }
|
|
396
|
+
},
|
|
397
|
+
gemini: {
|
|
398
|
+
"gemini-2.0-flash-exp": { input: 0, output: 0 },
|
|
399
|
+
"gemini-2.0-flash": { input: 0.075, output: 0.3 },
|
|
400
|
+
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
|
|
401
|
+
"gemini-1.5-pro": { input: 1.25, output: 5 }
|
|
402
|
+
},
|
|
403
|
+
groq: {
|
|
404
|
+
"openai/gpt-oss-120b": { input: 0.5, output: 0.8 }
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
function setModelPricing(backend, model, inputCost, outputCost) {
|
|
408
|
+
if (!MODEL_PRICING[backend]) {
|
|
409
|
+
MODEL_PRICING[backend] = {};
|
|
410
|
+
}
|
|
411
|
+
MODEL_PRICING[backend][model] = { input: inputCost, output: outputCost };
|
|
412
|
+
}
|
|
413
|
+
function loadPricingFromEnv() {
|
|
414
|
+
const env2 = typeof process !== "undefined" ? process.env : {};
|
|
415
|
+
const pricingJson = env2.ELIZA_RLM_PRICING_JSON;
|
|
416
|
+
if (!pricingJson) return;
|
|
417
|
+
try {
|
|
418
|
+
const customPricing = JSON.parse(pricingJson);
|
|
419
|
+
for (const [backend, models] of Object.entries(customPricing)) {
|
|
420
|
+
for (const [model, prices] of Object.entries(models)) {
|
|
421
|
+
setModelPricing(backend, model, prices.input ?? 1, prices.output ?? 3);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} catch (e) {
|
|
425
|
+
console.warn(`[RLM] Failed to parse ELIZA_RLM_PRICING_JSON: ${e}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
loadPricingFromEnv();
|
|
429
|
+
function estimateTokenCount(text) {
|
|
430
|
+
return Math.ceil(text.length / 4);
|
|
431
|
+
}
|
|
432
|
+
|
|
370
433
|
// index.ts
|
|
371
434
|
var env = typeof process !== "undefined" ? process.env : {};
|
|
435
|
+
function resolveBackend(value) {
|
|
436
|
+
return VALID_BACKENDS.includes(value) ? value : DEFAULT_CONFIG.backend;
|
|
437
|
+
}
|
|
438
|
+
function resolveEnvironment(value) {
|
|
439
|
+
return VALID_ENVIRONMENTS.includes(value) ? value : DEFAULT_CONFIG.environment;
|
|
440
|
+
}
|
|
441
|
+
function getRuntimeConfig(runtime) {
|
|
442
|
+
return runtime.rlmConfig;
|
|
443
|
+
}
|
|
444
|
+
function setRuntimeConfig(runtime, config) {
|
|
445
|
+
runtime.rlmConfig = config;
|
|
446
|
+
}
|
|
372
447
|
var clientState = {
|
|
373
448
|
client: null,
|
|
374
449
|
initPromise: null,
|
|
@@ -385,7 +460,7 @@ function computeConfigHash(config) {
|
|
|
385
460
|
return key;
|
|
386
461
|
}
|
|
387
462
|
function getOrCreateClient(runtime) {
|
|
388
|
-
const runtimeConfig = runtime
|
|
463
|
+
const runtimeConfig = getRuntimeConfig(runtime);
|
|
389
464
|
const configHash = computeConfigHash(runtimeConfig ?? {});
|
|
390
465
|
if (clientState.client && clientState.configHash !== configHash) {
|
|
391
466
|
logger.info("[RLM] Config changed, recreating client");
|
|
@@ -422,7 +497,28 @@ async function handleTextGeneration(runtime, params) {
|
|
|
422
497
|
user: params.user
|
|
423
498
|
};
|
|
424
499
|
const cleanOpts = Object.fromEntries(Object.entries(opts).filter(([, v]) => v !== void 0));
|
|
425
|
-
const
|
|
500
|
+
const runtimeConfig = getRuntimeConfig(runtime);
|
|
501
|
+
const backend = runtimeConfig?.backend ?? DEFAULT_CONFIG.backend;
|
|
502
|
+
const model = `${backend}:rlm`;
|
|
503
|
+
const details = {
|
|
504
|
+
model,
|
|
505
|
+
systemPrompt: resolveEffectiveSystemPrompt({
|
|
506
|
+
params,
|
|
507
|
+
fallback: buildCanonicalSystemPrompt({ character: runtime.character })
|
|
508
|
+
}) ?? "",
|
|
509
|
+
userPrompt: input,
|
|
510
|
+
temperature: params.temperature ?? 0,
|
|
511
|
+
maxTokens: params.maxTokens ?? 0,
|
|
512
|
+
purpose: "external_llm",
|
|
513
|
+
actionType: "rlm.client.infer",
|
|
514
|
+
promptTokens: estimateTokenCount(input)
|
|
515
|
+
};
|
|
516
|
+
const result = await recordLlmCall(runtime, details, async () => {
|
|
517
|
+
const response = await client.infer(input, cleanOpts);
|
|
518
|
+
details.response = response.text;
|
|
519
|
+
details.completionTokens = estimateTokenCount(response.text);
|
|
520
|
+
return response;
|
|
521
|
+
});
|
|
426
522
|
return result.text;
|
|
427
523
|
}
|
|
428
524
|
var rlmPlugin = {
|
|
@@ -438,14 +534,14 @@ var rlmPlugin = {
|
|
|
438
534
|
},
|
|
439
535
|
async init(config, runtime) {
|
|
440
536
|
logger.info("[RLM] Initializing RLM plugin");
|
|
441
|
-
runtime
|
|
442
|
-
backend: config[ENV_VARS.BACKEND]
|
|
443
|
-
environment: config[ENV_VARS.ENVIRONMENT]
|
|
537
|
+
setRuntimeConfig(runtime, {
|
|
538
|
+
backend: resolveBackend(config[ENV_VARS.BACKEND]),
|
|
539
|
+
environment: resolveEnvironment(config[ENV_VARS.ENVIRONMENT]),
|
|
444
540
|
maxIterations: Number.parseInt(config[ENV_VARS.MAX_ITERATIONS] ?? "", 10) || DEFAULT_CONFIG.maxIterations,
|
|
445
541
|
maxDepth: Number.parseInt(config[ENV_VARS.MAX_DEPTH] ?? "", 10) || DEFAULT_CONFIG.maxDepth,
|
|
446
542
|
verbose: ["1", "true", "yes"].includes((config[ENV_VARS.VERBOSE] ?? "").toLowerCase()),
|
|
447
543
|
pythonPath: config[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath
|
|
448
|
-
};
|
|
544
|
+
});
|
|
449
545
|
const client = getOrCreateClient(runtime);
|
|
450
546
|
const status = await client.getStatus();
|
|
451
547
|
if (status.available) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../client.ts","../types.ts"],"sourcesContent":["/**\n * RLM (Recursive Language Model) plugin for elizaOS.\n *\n * This plugin integrates Recursive Language Models into elizaOS, enabling\n * LLMs to process arbitrarily long contexts through recursive self-calls\n * in a REPL environment.\n *\n * Reference:\n * - Paper: https://arxiv.org/abs/2512.24601\n * - Implementation: https://github.com/alexzhang13/rlm\n */\n\nimport type { GenerateTextParams, IAgentRuntime, Plugin } from \"@elizaos/core\";\nimport { ModelType, logger } from \"@elizaos/core\";\n\nimport { RLMClient, stubResult } from \"./client\";\nimport type { RLMConfig } from \"./types\";\nimport { DEFAULT_CONFIG, ENV_VARS } from \"./types\";\n\n// Safe env access for browser/non-Node environments\nconst env: Record<string, string | undefined> = typeof process !== \"undefined\" ? process.env : {};\n\n// ============================================================================\n// Thread-safe Singleton Client Management\n// ============================================================================\n\n/**\n * Singleton state for thread-safe client initialization.\n *\n * In concurrent environments, multiple requests could try to initialize\n * the client simultaneously. We use a promise-based lock to ensure\n * only one initialization happens.\n */\ninterface ClientState {\n client: RLMClient | null;\n initPromise: Promise<RLMClient> | null;\n configHash: string | null;\n}\n\nconst clientState: ClientState = {\n client: null,\n initPromise: null,\n configHash: null,\n};\n\n/**\n * Compute a simple hash of config for detecting changes.\n */\nfunction computeConfigHash(config: Partial<RLMConfig>): string {\n const key = [\n config.backend ?? \"\",\n config.environment ?? \"\",\n String(config.maxIterations ?? \"\"),\n String(config.maxDepth ?? \"\"),\n config.pythonPath ?? \"\",\n ].join(\"|\");\n return key;\n}\n\n/**\n * Get or create the shared RLM client instance (thread-safe).\n *\n * This implementation ensures:\n * 1. Only one client is created even under concurrent initialization\n * 2. Config changes are detected and client is recreated\n * 3. Initialization errors are properly handled\n */\nfunction getOrCreateClient(runtime: IAgentRuntime): RLMClient {\n // Get config from runtime or environment\n const runtimeConfig = (runtime as unknown as Record<string, unknown>).rlmConfig as\n | Partial<RLMConfig>\n | undefined;\n const configHash = computeConfigHash(runtimeConfig ?? {});\n\n // Check if config changed - need to recreate client\n if (clientState.client && clientState.configHash !== configHash) {\n logger.info(\"[RLM] Config changed, recreating client\");\n // Shutdown old client (fire and forget)\n clientState.client.shutdown().catch((err) => {\n logger.warn(\"[RLM] Error shutting down old client:\", err);\n });\n clientState.client = null;\n clientState.initPromise = null;\n }\n\n // Fast path: client already exists with same config\n if (clientState.client) {\n return clientState.client;\n }\n\n // Slow path: need to create client\n // Create synchronously to avoid Promise in synchronous getter\n const client = new RLMClient(runtimeConfig);\n clientState.client = client;\n clientState.configHash = configHash;\n\n return client;\n}\n\n/**\n * Reset the client singleton. Useful for testing or forced reinitialization.\n */\nexport async function resetClient(): Promise<void> {\n if (clientState.client) {\n await clientState.client.shutdown();\n }\n clientState.client = null;\n clientState.initPromise = null;\n clientState.configHash = null;\n}\n\n/**\n * Handle text generation using RLM.\n */\nasync function handleTextGeneration(\n runtime: IAgentRuntime,\n params: GenerateTextParams,\n): Promise<string> {\n const client = getOrCreateClient(runtime);\n\n // Use prompt from params\n const input = params.prompt ?? \"\";\n\n const opts = {\n maxTokens: params.maxTokens,\n temperature: params.temperature,\n topP: params.topP,\n stopSequences: params.stopSequences,\n user: params.user,\n };\n\n // Remove undefined values\n const cleanOpts = Object.fromEntries(Object.entries(opts).filter(([, v]) => v !== undefined));\n\n const result = await client.infer(input, cleanOpts);\n return result.text;\n}\n\n/**\n * RLM plugin definition.\n */\nexport const rlmPlugin: Plugin = {\n name: \"rlm\",\n description:\n \"RLM (Recursive Language Model) adapter for elizaOS - enables processing of arbitrarily long contexts through recursive self-calls\",\n\n config: {\n [ENV_VARS.BACKEND]: env[ENV_VARS.BACKEND] ?? DEFAULT_CONFIG.backend,\n [ENV_VARS.ENVIRONMENT]: env[ENV_VARS.ENVIRONMENT] ?? DEFAULT_CONFIG.environment,\n [ENV_VARS.MAX_ITERATIONS]: env[ENV_VARS.MAX_ITERATIONS] ?? String(DEFAULT_CONFIG.maxIterations),\n [ENV_VARS.MAX_DEPTH]: env[ENV_VARS.MAX_DEPTH] ?? String(DEFAULT_CONFIG.maxDepth),\n [ENV_VARS.VERBOSE]: env[ENV_VARS.VERBOSE] ?? \"false\",\n [ENV_VARS.PYTHON_PATH]: env[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n },\n\n async init(config: Record<string, string>, runtime: IAgentRuntime): Promise<void> {\n logger.info(\"[RLM] Initializing RLM plugin\");\n\n // Store config on runtime\n (runtime as unknown as Record<string, unknown>).rlmConfig = {\n backend: config[ENV_VARS.BACKEND] ?? DEFAULT_CONFIG.backend,\n environment: config[ENV_VARS.ENVIRONMENT] ?? DEFAULT_CONFIG.environment,\n maxIterations:\n Number.parseInt(config[ENV_VARS.MAX_ITERATIONS] ?? \"\", 10) || DEFAULT_CONFIG.maxIterations,\n maxDepth: Number.parseInt(config[ENV_VARS.MAX_DEPTH] ?? \"\", 10) || DEFAULT_CONFIG.maxDepth,\n verbose: [\"1\", \"true\", \"yes\"].includes((config[ENV_VARS.VERBOSE] ?? \"\").toLowerCase()),\n pythonPath: config[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n };\n\n // Pre-initialize client\n const client = getOrCreateClient(runtime);\n const status = await client.getStatus();\n\n if (status.available) {\n logger.info(`[RLM] Backend available: ${status.backend}`);\n } else {\n logger.warn(\"[RLM] Backend not available - running in stub mode\");\n }\n },\n\n models: {\n [ModelType.TEXT_SMALL]: handleTextGeneration,\n [ModelType.TEXT_LARGE]: handleTextGeneration,\n [ModelType.TEXT_REASONING_SMALL]: handleTextGeneration,\n [ModelType.TEXT_REASONING_LARGE]: handleTextGeneration,\n [ModelType.TEXT_COMPLETION]: handleTextGeneration,\n },\n\n tests: [\n {\n name: \"rlm_plugin_tests\",\n tests: [\n {\n name: \"rlm_test_stub_mode\",\n fn: async (_runtime: IAgentRuntime): Promise<void> => {\n // Test that stub mode works\n const result = stubResult();\n if (!result.metadata.stub) {\n throw new Error(\"Stub result should have stub=true\");\n }\n logger.info(\"[RLM Test] Stub mode test passed\");\n },\n },\n {\n name: \"rlm_test_text_generation\",\n fn: async (runtime: IAgentRuntime): Promise<void> => {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"Say 'hello' in exactly one word.\",\n });\n\n if (typeof text !== \"string\") {\n throw new Error(\"TEXT_LARGE should return string\");\n }\n\n logger.info(`[RLM Test] TEXT_LARGE generated: \"${text.substring(0, 50)}...\"`);\n },\n },\n {\n name: \"rlm_test_message_format\",\n fn: async (runtime: IAgentRuntime): Promise<void> => {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"What is 2 + 2?\",\n });\n\n if (typeof text !== \"string\") {\n throw new Error(\"TEXT_LARGE with prompt should return string\");\n }\n\n logger.info(\"[RLM Test] Message format test passed\");\n },\n },\n ],\n },\n ],\n};\n\nexport default rlmPlugin;\n\n// Re-export types and client\nexport { RLMClient, configFromEnv, stubResult } from \"./client\";\nexport type {\n GenerateTextParams,\n RLMConfig,\n RLMMessage,\n RLMMetadata,\n RLMResult,\n RLMInferOptions,\n RLMStatusResponse,\n} from \"./types\";\nexport { DEFAULT_CONFIG, ENV_VARS } from \"./types\";\n","/** RLM Client - communicates with Python subprocess via JSON-RPC IPC. */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\n\nimport type {\n IPCReadyMessage,\n IPCRequest,\n IPCResponse,\n MetricsCallback,\n RLMConfig,\n RLMInferOptions,\n RLMMessage,\n RLMMetrics,\n RLMResult,\n RLMStatusResponse,\n} from \"./types\";\nimport { DEFAULT_CONFIG, ENV_VARS, validateConfig } from \"./types\";\n\nexport { DEFAULT_CONFIG };\nexport type { RLMMetrics, MetricsCallback };\n\ninterface Logger {\n info: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n debug: (message: string, ...args: unknown[]) => void;\n}\n\nconst defaultLogger: Logger = {\n info: (msg, ...args) => console.log(`[RLM] ${msg}`, ...args),\n warn: (msg, ...args) => console.warn(`[RLM] ${msg}`, ...args),\n error: (msg, ...args) => console.error(`[RLM] ${msg}`, ...args),\n debug: (msg, ...args) => console.debug(`[RLM] ${msg}`, ...args),\n};\n\nexport function configFromEnv(env: NodeJS.ProcessEnv = process.env): RLMConfig {\n return {\n backend: (env[ENV_VARS.BACKEND] as RLMConfig[\"backend\"]) ?? DEFAULT_CONFIG.backend,\n backendKwargs: {},\n environment:\n (env[ENV_VARS.ENVIRONMENT] as RLMConfig[\"environment\"]) ?? DEFAULT_CONFIG.environment,\n maxIterations:\n Number.parseInt(env[ENV_VARS.MAX_ITERATIONS] ?? \"\", 10) || DEFAULT_CONFIG.maxIterations,\n maxDepth: Number.parseInt(env[ENV_VARS.MAX_DEPTH] ?? \"\", 10) || DEFAULT_CONFIG.maxDepth,\n verbose: [\"1\", \"true\", \"yes\"].includes((env[ENV_VARS.VERBOSE] ?? \"\").toLowerCase()),\n pythonPath: env[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n maxRetries: Number.parseInt(env[ENV_VARS.MAX_RETRIES] ?? \"\", 10) || DEFAULT_CONFIG.maxRetries,\n retryBaseDelay:\n Number.parseInt(env[ENV_VARS.RETRY_BASE_DELAY] ?? \"\", 10) || DEFAULT_CONFIG.retryBaseDelay,\n retryMaxDelay:\n Number.parseInt(env[ENV_VARS.RETRY_MAX_DELAY] ?? \"\", 10) || DEFAULT_CONFIG.retryMaxDelay,\n };\n}\n\nexport class RLMClient {\n private config: RLMConfig;\n private process: ChildProcess | null = null;\n private reader: readline.Interface | null = null;\n private requestId = 0;\n private pendingRequests = new Map<\n number,\n { resolve: (value: IPCResponse) => void; reject: (error: Error) => void }\n >();\n private isReady = false;\n private isAvailable = false;\n private hasStartupError = false;\n private logger: Logger;\n private metrics: RLMMetrics = {\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n stubResponses: 0,\n totalRetries: 0,\n averageLatencyMs: 0,\n p95LatencyMs: 0,\n lastRequestTimestamp: 0,\n };\n private static readonly MAX_LATENCY_SAMPLES = 1000;\n private latencies: number[] = new Array(RLMClient.MAX_LATENCY_SAMPLES).fill(0);\n private latencyIndex = 0;\n private latencyCount = 0;\n private metricsCallback: MetricsCallback | null = null;\n\n constructor(config?: Partial<RLMConfig>, logger?: Logger, strictValidation = false) {\n this.config = { ...configFromEnv(), ...config };\n this.logger = logger ?? defaultLogger;\n\n const errors = validateConfig(this.config);\n if (errors.length > 0) {\n if (strictValidation) {\n throw new Error(`RLM configuration invalid: ${errors.join(\"; \")}`);\n }\n for (const error of errors) {\n this.logger.warn(`Configuration warning: ${error}`);\n }\n }\n }\n\n private async startServer(): Promise<void> {\n if (this.process) return;\n this.hasStartupError = false;\n\n this.logger.debug(\n `Starting RLM server: ${this.config.pythonPath} -m elizaos_plugin_rlm.server`,\n );\n\n try {\n this.process = spawn(this.config.pythonPath, [\"-m\", \"elizaos_plugin_rlm.server\"], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n [ENV_VARS.BACKEND]: this.config.backend,\n [ENV_VARS.ENVIRONMENT]: this.config.environment,\n [ENV_VARS.MAX_ITERATIONS]: String(this.config.maxIterations),\n [ENV_VARS.MAX_DEPTH]: String(this.config.maxDepth),\n [ENV_VARS.VERBOSE]: this.config.verbose ? \"true\" : \"false\",\n },\n cwd: path.join(__dirname, \"..\", \"python\"),\n });\n } catch (error) {\n this.logger.warn(`Failed to start RLM server: ${error}`);\n this.isAvailable = false;\n return;\n }\n\n if (!this.process.stdout || !this.process.stdin) {\n this.logger.warn(\"RLM server process missing stdio streams\");\n this.isAvailable = false;\n return;\n }\n\n // Set up line reader for responses\n this.reader = readline.createInterface({\n input: this.process.stdout,\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n\n // Handle incoming messages\n this.reader.on(\"line\", (line: string) => {\n this.handleMessage(line);\n });\n\n // Handle errors\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n this.logger.debug(`RLM server stderr: ${data.toString()}`);\n });\n\n this.process.on(\"error\", (error: Error) => {\n this.logger.error(`RLM server error: ${error.message}`);\n this.isAvailable = false;\n this.hasStartupError = true;\n });\n\n this.process.on(\"exit\", (code: number | null) => {\n this.logger.debug(`RLM server exited with code ${code}`);\n this.isReady = false;\n this.isAvailable = false;\n this.process = null;\n });\n\n await this.waitForReady();\n }\n\n private waitForReady(): Promise<void> {\n return new Promise((resolve, reject) => {\n const TIMEOUT_MS = 10000;\n const POLL_INTERVAL_MS = 100;\n const deadline = Date.now() + TIMEOUT_MS;\n\n const checkReady = () => {\n if (this.isReady) {\n resolve();\n } else if (!this.process || this.hasStartupError) {\n reject(new Error(\"RLM server process failed before ready\"));\n } else if (Date.now() > deadline) {\n reject(new Error(\"RLM server startup timeout\"));\n } else {\n setTimeout(checkReady, POLL_INTERVAL_MS);\n }\n };\n checkReady();\n });\n }\n\n private handleMessage(line: string): void {\n try {\n const message = JSON.parse(line) as IPCResponse | IPCReadyMessage;\n\n // Check for ready message\n if (\"ready\" in message) {\n const readyMsg = message as IPCReadyMessage;\n this.isReady = true;\n this.isAvailable = readyMsg.available;\n this.logger.info(`RLM server ready, available: ${this.isAvailable}`);\n return;\n }\n\n // Handle response\n const response = message as IPCResponse;\n const pending = this.pendingRequests.get(response.id);\n if (pending) {\n this.pendingRequests.delete(response.id);\n pending.resolve(response);\n }\n } catch (error) {\n this.logger.error(`Failed to parse RLM server message: ${line}`);\n }\n }\n\n private async sendRequest<T>(\n method: IPCRequest[\"method\"],\n params: Record<string, unknown> = {},\n ): Promise<T> {\n await this.ensureServer();\n\n if (!this.process?.stdin) {\n throw new Error(\"RLM server not running\");\n }\n\n const id = ++this.requestId;\n const request: IPCRequest = { id, method, params };\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`RLM request timeout: ${method}`));\n }, 60000);\n\n this.pendingRequests.set(id, {\n resolve: (response: IPCResponse) => {\n clearTimeout(timeout);\n if (response.error) {\n reject(new Error(response.error));\n } else {\n resolve(response.result as T);\n }\n },\n reject: (error: Error) => {\n clearTimeout(timeout);\n reject(error);\n },\n });\n\n this.process?.stdin?.write(`${JSON.stringify(request)}\\n`);\n });\n }\n\n private async ensureServer(): Promise<void> {\n if (!this.process || !this.isReady) {\n await this.startServer();\n }\n }\n\n get available(): boolean {\n return this.isAvailable;\n }\n\n getMetrics(): RLMMetrics {\n return { ...this.metrics };\n }\n\n onMetrics(callback: MetricsCallback): void {\n this.metricsCallback = callback;\n }\n\n private updateMetrics(\n latencyMs: number,\n success: boolean,\n isStub: boolean,\n error?: string,\n ): void {\n this.metrics.totalRequests++;\n this.metrics.lastRequestTimestamp = Date.now();\n\n if (isStub) {\n this.metrics.stubResponses++;\n } else if (success) {\n this.metrics.successfulRequests++;\n } else {\n this.metrics.failedRequests++;\n this.metrics.lastErrorTimestamp = Date.now();\n this.metrics.lastError = error;\n }\n\n // Track latency in circular buffer\n this.latencies[this.latencyIndex] = latencyMs;\n this.latencyIndex = (this.latencyIndex + 1) % RLMClient.MAX_LATENCY_SAMPLES;\n this.latencyCount = Math.min(this.latencyCount + 1, RLMClient.MAX_LATENCY_SAMPLES);\n\n // Calculate stats from valid samples\n if (this.latencyCount > 0) {\n const valid = this.latencies.slice(0, this.latencyCount);\n this.metrics.averageLatencyMs = valid.reduce((a, b) => a + b, 0) / this.latencyCount;\n this.metrics.p95LatencyMs =\n [...valid].sort((a, b) => a - b)[Math.floor(valid.length * 0.95)] ?? 0;\n }\n\n this.metricsCallback?.(this.getMetrics());\n }\n\n static normalizeMessages(messages: string | RLMMessage[]): RLMMessage[] {\n return typeof messages === \"string\" ? [{ role: \"user\", content: messages }] : messages;\n }\n\n async infer(messages: string | RLMMessage[], opts?: RLMInferOptions): Promise<RLMResult> {\n const startTime = Date.now();\n const { maxRetries = 3, retryBaseDelay = 1000, retryMaxDelay = 30000 } = this.config;\n const RETRYABLE_PATTERNS = [\"timeout\", \"rate limit\", \"connection\", \"503\", \"429\", \"econnreset\"];\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n await this.ensureServer();\n\n if (!this.isReady) {\n this.updateMetrics(Date.now() - startTime, true, true);\n return stubResult();\n }\n\n const result = await this.sendRequest<RLMResult>(\"infer\", {\n messages: RLMClient.normalizeMessages(messages),\n opts: opts ?? {},\n });\n\n this.updateMetrics(Date.now() - startTime, true, false);\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n const isRetryable = RETRYABLE_PATTERNS.some((p) =>\n lastError?.message.toLowerCase().includes(p),\n );\n\n if (!isRetryable || attempt === maxRetries - 1) {\n this.logger.error(`RLM inference failed after ${attempt + 1} attempts: ${error}`);\n this.updateMetrics(Date.now() - startTime, true, true, lastError.message);\n return stubResult(lastError.message);\n }\n\n const delay =\n Math.min(retryBaseDelay * 2 ** attempt, retryMaxDelay) * (0.75 + Math.random() * 0.5);\n this.metrics.totalRetries++;\n this.logger.warn(\n `RLM attempt ${attempt + 1}/${maxRetries} failed. Retrying in ${Math.round(delay)}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n this.updateMetrics(Date.now() - startTime, false, false, lastError?.message);\n return stubResult(lastError?.message);\n }\n\n async getStatus(): Promise<RLMStatusResponse> {\n try {\n await this.ensureServer();\n return await this.sendRequest<RLMStatusResponse>(\"status\");\n } catch {\n return {\n available: false,\n backend: this.config.backend,\n environment: this.config.environment,\n maxIterations: this.config.maxIterations,\n maxDepth: this.config.maxDepth,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n if (!this.process) return;\n try {\n await this.sendRequest(\"shutdown\");\n } catch {\n /* ignore */\n }\n this.reader?.close();\n this.process?.kill();\n this.process = null;\n this.isReady = false;\n this.isAvailable = false;\n }\n}\n\nexport function stubResult(error?: string): RLMResult {\n return {\n text: \"[RLM STUB] RLM backend not available\",\n metadata: { stub: true, error },\n };\n}\n","/** Types for the RLM (Recursive Language Model) plugin. */\n\nexport type RLMBackend = \"openai\" | \"anthropic\" | \"gemini\" | \"groq\" | \"openrouter\";\nexport type RLMEnvironment = \"local\" | \"docker\" | \"modal\" | \"prime\";\n\nexport interface RLMConfig {\n backend: RLMBackend;\n backendKwargs: Record<string, string>;\n environment: RLMEnvironment;\n maxIterations: number;\n maxDepth: number;\n verbose: boolean;\n pythonPath: string;\n maxRetries?: number;\n retryBaseDelay?: number;\n retryMaxDelay?: number;\n}\n\nexport interface RLMMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n}\n\nexport interface RLMMetadata {\n stub: boolean;\n iterations?: number;\n depth?: number;\n error?: string;\n}\n\nexport interface RLMResult {\n text: string;\n metadata: RLMMetadata;\n}\n\nexport interface RLMInferOptions {\n /** Model identifier for this request */\n model?: string;\n /** Maximum tokens to generate */\n maxTokens?: number;\n /** Sampling temperature */\n temperature?: number;\n /** Top-p sampling parameter */\n topP?: number;\n /** Stop sequences */\n stopSequences?: string[];\n /** User identifier for tracking */\n user?: string;\n /** Enable streaming (not yet supported by RLM) */\n stream?: boolean;\n\n // Per-request RLM overrides (Paper Algorithm 1)\n /** Override max iterations for this request */\n maxIterations?: number;\n /** Override max recursion depth for this request */\n maxDepth?: number;\n /** Override root model for this request */\n rootModel?: string;\n /** Override subcall model for this request */\n subcallModel?: string;\n /** Enable trajectory logging for this request */\n logTrajectories?: boolean;\n /** Enable cost tracking for this request */\n trackCosts?: boolean;\n\n // NOTE: Custom REPL tool injection is NOT supported by the upstream RLM library.\n // See: https://arxiv.org/abs/2512.24601 Section 3.3 - the paper describes the concept\n // but the current library implementation does not expose this capability.\n}\n\nexport interface RLMStatusResponse {\n available: boolean;\n backend: string;\n environment: string;\n maxIterations: number;\n maxDepth: number;\n}\n\nexport interface IPCRequest {\n id: number;\n method: \"infer\" | \"status\" | \"shutdown\";\n params: Record<string, unknown>;\n}\n\nexport interface IPCResponse<T = unknown> {\n id: number;\n result?: T;\n error?: string;\n}\n\nexport interface IPCReadyMessage {\n ready: boolean;\n available: boolean;\n}\n\nexport interface GenerateTextParams {\n prompt?: string;\n system?: string;\n messages?: RLMMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n topP?: number;\n stopSequences?: string[];\n user?: string;\n stream?: boolean;\n}\n\nexport const DEFAULT_CONFIG: RLMConfig = {\n backend: \"gemini\",\n backendKwargs: {},\n environment: \"local\",\n maxIterations: 4,\n maxDepth: 1,\n verbose: false,\n pythonPath: \"python\",\n maxRetries: 3,\n retryBaseDelay: 1000,\n retryMaxDelay: 30000,\n};\n\nexport interface RLMMetrics {\n totalRequests: number;\n successfulRequests: number;\n failedRequests: number;\n stubResponses: number;\n totalRetries: number;\n averageLatencyMs: number;\n p95LatencyMs: number;\n lastRequestTimestamp: number;\n lastErrorTimestamp?: number;\n lastError?: string;\n}\n\nexport type MetricsCallback = (metrics: RLMMetrics) => void;\n\nexport const ENV_VARS = {\n BACKEND: \"ELIZA_RLM_BACKEND\",\n ENVIRONMENT: \"ELIZA_RLM_ENV\",\n MAX_ITERATIONS: \"ELIZA_RLM_MAX_ITERATIONS\",\n MAX_DEPTH: \"ELIZA_RLM_MAX_DEPTH\",\n VERBOSE: \"ELIZA_RLM_VERBOSE\",\n PYTHON_PATH: \"ELIZA_RLM_PYTHON_PATH\",\n MAX_RETRIES: \"ELIZA_RLM_MAX_RETRIES\",\n RETRY_BASE_DELAY: \"ELIZA_RLM_RETRY_BASE_DELAY\",\n RETRY_MAX_DELAY: \"ELIZA_RLM_RETRY_MAX_DELAY\",\n} as const;\n\nexport const VALID_BACKENDS: readonly RLMBackend[] = [\n \"openai\",\n \"anthropic\",\n \"gemini\",\n \"groq\",\n \"openrouter\",\n];\nexport const VALID_ENVIRONMENTS: readonly RLMEnvironment[] = [\"local\", \"docker\", \"modal\", \"prime\"];\n\nexport class RLMConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RLMConfigError\";\n }\n}\n\n/** Validate config. Returns errors array, or throws if strict=true. */\nexport function validateConfig(config: Partial<RLMConfig>, strict = false): string[] {\n const errors: string[] = [];\n\n if (config.backend !== undefined && !VALID_BACKENDS.includes(config.backend)) {\n errors.push(`Invalid backend '${config.backend}'. Valid options: ${VALID_BACKENDS.join(\", \")}`);\n }\n\n if (config.environment !== undefined && !VALID_ENVIRONMENTS.includes(config.environment)) {\n errors.push(\n `Invalid environment '${config.environment}'. Valid options: ${VALID_ENVIRONMENTS.join(\", \")}`,\n );\n }\n\n if (config.maxIterations !== undefined && config.maxIterations < 1) {\n errors.push(\"maxIterations must be >= 1\");\n }\n\n if (config.maxDepth !== undefined && config.maxDepth < 1) {\n errors.push(\"maxDepth must be >= 1\");\n }\n\n if (config.maxRetries !== undefined && config.maxRetries < 0) {\n errors.push(\"maxRetries must be >= 0\");\n }\n\n if (config.retryBaseDelay !== undefined && config.retryBaseDelay < 0) {\n errors.push(\"retryBaseDelay must be >= 0\");\n }\n\n if (\n config.retryBaseDelay !== undefined &&\n config.retryMaxDelay !== undefined &&\n config.retryMaxDelay < config.retryBaseDelay\n ) {\n errors.push(\"retryMaxDelay must be >= retryBaseDelay\");\n }\n\n if (strict && errors.length > 0) {\n throw new RLMConfigError(errors.join(\"; \"));\n }\n\n return errors;\n}\n"],"mappings":"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","names":["env","logger"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts","../client.ts","../types.ts","../cost.ts"],"sourcesContent":["/**\n * RLM (Recursive Language Model) plugin for elizaOS.\n *\n * This plugin integrates Recursive Language Models into elizaOS, enabling\n * LLMs to process arbitrarily long contexts through recursive self-calls\n * in a REPL environment.\n *\n * Reference:\n * - Paper: https://arxiv.org/abs/2512.24601\n * - Implementation: https://github.com/alexzhang13/rlm\n */\n\nimport type {\n GenerateTextParams,\n IAgentRuntime,\n Plugin,\n RecordLlmCallDetails,\n} from \"@elizaos/core\";\nimport {\n buildCanonicalSystemPrompt,\n logger,\n ModelType,\n recordLlmCall,\n resolveEffectiveSystemPrompt,\n} from \"@elizaos/core\";\n\nimport { RLMClient, stubResult } from \"./client\";\nimport { estimateTokenCount } from \"./cost\";\nimport type { RLMConfig } from \"./types\";\nimport { DEFAULT_CONFIG, ENV_VARS, VALID_BACKENDS, VALID_ENVIRONMENTS } from \"./types\";\n\n// Safe env access for browser/non-Node environments\nconst env: Record<string, string | undefined> = typeof process !== \"undefined\" ? process.env : {};\n\nfunction resolveBackend(value: string | undefined): RLMConfig[\"backend\"] {\n return VALID_BACKENDS.includes(value as RLMConfig[\"backend\"])\n ? (value as RLMConfig[\"backend\"])\n : DEFAULT_CONFIG.backend;\n}\n\nfunction resolveEnvironment(value: string | undefined): RLMConfig[\"environment\"] {\n return VALID_ENVIRONMENTS.includes(value as RLMConfig[\"environment\"])\n ? (value as RLMConfig[\"environment\"])\n : DEFAULT_CONFIG.environment;\n}\n\n// ============================================================================\n// Thread-safe Singleton Client Management\n// ============================================================================\n\n/**\n * Singleton state for thread-safe client initialization.\n *\n * In concurrent environments, multiple requests could try to initialize\n * the client simultaneously. We use a promise-based lock to ensure\n * only one initialization happens.\n */\ninterface ClientState {\n client: RLMClient | null;\n initPromise: Promise<RLMClient> | null;\n configHash: string | null;\n}\n\ntype RuntimeWithRLMConfig = IAgentRuntime & {\n rlmConfig?: Partial<RLMConfig>;\n};\n\nfunction getRuntimeConfig(runtime: IAgentRuntime): Partial<RLMConfig> | undefined {\n return (runtime as RuntimeWithRLMConfig).rlmConfig;\n}\n\nfunction setRuntimeConfig(runtime: IAgentRuntime, config: Partial<RLMConfig>): void {\n (runtime as RuntimeWithRLMConfig).rlmConfig = config;\n}\n\nconst clientState: ClientState = {\n client: null,\n initPromise: null,\n configHash: null,\n};\n\n/**\n * Compute a simple hash of config for detecting changes.\n */\nfunction computeConfigHash(config: Partial<RLMConfig>): string {\n const key = [\n config.backend ?? \"\",\n config.environment ?? \"\",\n String(config.maxIterations ?? \"\"),\n String(config.maxDepth ?? \"\"),\n config.pythonPath ?? \"\",\n ].join(\"|\");\n return key;\n}\n\n/**\n * Get or create the shared RLM client instance (thread-safe).\n *\n * This implementation ensures:\n * 1. Only one client is created even under concurrent initialization\n * 2. Config changes are detected and client is recreated\n * 3. Initialization errors are properly handled\n */\nfunction getOrCreateClient(runtime: IAgentRuntime): RLMClient {\n // Get config from runtime or environment\n const runtimeConfig = getRuntimeConfig(runtime);\n const configHash = computeConfigHash(runtimeConfig ?? {});\n\n // Check if config changed - need to recreate client\n if (clientState.client && clientState.configHash !== configHash) {\n logger.info(\"[RLM] Config changed, recreating client\");\n // Shutdown old client (fire and forget)\n clientState.client.shutdown().catch((err) => {\n logger.warn(\"[RLM] Error shutting down old client:\", err);\n });\n clientState.client = null;\n clientState.initPromise = null;\n }\n\n // Fast path: client already exists with same config\n if (clientState.client) {\n return clientState.client;\n }\n\n // Slow path: need to create client\n // Create synchronously to avoid Promise in synchronous getter\n const client = new RLMClient(runtimeConfig);\n clientState.client = client;\n clientState.configHash = configHash;\n\n return client;\n}\n\n/**\n * Reset the client singleton. Useful for testing or forced reinitialization.\n */\nexport async function resetClient(): Promise<void> {\n if (clientState.client) {\n await clientState.client.shutdown();\n }\n clientState.client = null;\n clientState.initPromise = null;\n clientState.configHash = null;\n}\n\n/**\n * Handle text generation using RLM.\n */\nasync function handleTextGeneration(\n runtime: IAgentRuntime,\n params: GenerateTextParams,\n): Promise<string> {\n const client = getOrCreateClient(runtime);\n\n // Use prompt from params\n const input = params.prompt ?? \"\";\n\n const opts = {\n maxTokens: params.maxTokens,\n temperature: params.temperature,\n topP: params.topP,\n stopSequences: params.stopSequences,\n user: params.user,\n };\n\n // Remove undefined values\n const cleanOpts = Object.fromEntries(Object.entries(opts).filter(([, v]) => v !== undefined));\n\n const runtimeConfig = getRuntimeConfig(runtime);\n const backend = runtimeConfig?.backend ?? DEFAULT_CONFIG.backend;\n const model = `${backend}:rlm`;\n const details: RecordLlmCallDetails = {\n model,\n systemPrompt:\n resolveEffectiveSystemPrompt({\n params,\n fallback: buildCanonicalSystemPrompt({ character: runtime.character }),\n }) ?? \"\",\n userPrompt: input,\n temperature: params.temperature ?? 0,\n maxTokens: params.maxTokens ?? 0,\n purpose: \"external_llm\",\n actionType: \"rlm.client.infer\",\n promptTokens: estimateTokenCount(input),\n };\n\n const result = await recordLlmCall(runtime, details, async () => {\n const response = await client.infer(input, cleanOpts);\n details.response = response.text;\n details.completionTokens = estimateTokenCount(response.text);\n return response;\n });\n return result.text;\n}\n\n/**\n * RLM plugin definition.\n */\nexport const rlmPlugin: Plugin = {\n name: \"rlm\",\n description:\n \"RLM (Recursive Language Model) adapter for elizaOS - enables processing of arbitrarily long contexts through recursive self-calls\",\n\n config: {\n [ENV_VARS.BACKEND]: env[ENV_VARS.BACKEND] ?? DEFAULT_CONFIG.backend,\n [ENV_VARS.ENVIRONMENT]: env[ENV_VARS.ENVIRONMENT] ?? DEFAULT_CONFIG.environment,\n [ENV_VARS.MAX_ITERATIONS]: env[ENV_VARS.MAX_ITERATIONS] ?? String(DEFAULT_CONFIG.maxIterations),\n [ENV_VARS.MAX_DEPTH]: env[ENV_VARS.MAX_DEPTH] ?? String(DEFAULT_CONFIG.maxDepth),\n [ENV_VARS.VERBOSE]: env[ENV_VARS.VERBOSE] ?? \"false\",\n [ENV_VARS.PYTHON_PATH]: env[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n },\n\n async init(config: Record<string, string>, runtime: IAgentRuntime): Promise<void> {\n logger.info(\"[RLM] Initializing RLM plugin\");\n\n // Store config on runtime\n setRuntimeConfig(runtime, {\n backend: resolveBackend(config[ENV_VARS.BACKEND]),\n environment: resolveEnvironment(config[ENV_VARS.ENVIRONMENT]),\n maxIterations:\n Number.parseInt(config[ENV_VARS.MAX_ITERATIONS] ?? \"\", 10) || DEFAULT_CONFIG.maxIterations,\n maxDepth: Number.parseInt(config[ENV_VARS.MAX_DEPTH] ?? \"\", 10) || DEFAULT_CONFIG.maxDepth,\n verbose: [\"1\", \"true\", \"yes\"].includes((config[ENV_VARS.VERBOSE] ?? \"\").toLowerCase()),\n pythonPath: config[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n });\n\n // Pre-initialize client\n const client = getOrCreateClient(runtime);\n const status = await client.getStatus();\n\n if (status.available) {\n logger.info(`[RLM] Backend available: ${status.backend}`);\n } else {\n logger.warn(\"[RLM] Backend not available - running in stub mode\");\n }\n },\n\n models: {\n [ModelType.TEXT_SMALL]: handleTextGeneration,\n [ModelType.TEXT_LARGE]: handleTextGeneration,\n [ModelType.TEXT_REASONING_SMALL]: handleTextGeneration,\n [ModelType.TEXT_REASONING_LARGE]: handleTextGeneration,\n [ModelType.TEXT_COMPLETION]: handleTextGeneration,\n },\n\n tests: [\n {\n name: \"rlm_plugin_tests\",\n tests: [\n {\n name: \"rlm_test_stub_mode\",\n fn: async (_runtime: IAgentRuntime): Promise<void> => {\n // Test that stub mode works\n const result = stubResult();\n if (!result.metadata.stub) {\n throw new Error(\"Stub result should have stub=true\");\n }\n logger.info(\"[RLM Test] Stub mode test passed\");\n },\n },\n {\n name: \"rlm_test_text_generation\",\n fn: async (runtime: IAgentRuntime): Promise<void> => {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"Say 'hello' in exactly one word.\",\n });\n\n if (typeof text !== \"string\") {\n throw new Error(\"TEXT_LARGE should return string\");\n }\n\n logger.info(`[RLM Test] TEXT_LARGE generated: \"${text.substring(0, 50)}...\"`);\n },\n },\n {\n name: \"rlm_test_message_format\",\n fn: async (runtime: IAgentRuntime): Promise<void> => {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"What is 2 + 2?\",\n });\n\n if (typeof text !== \"string\") {\n throw new Error(\"TEXT_LARGE with prompt should return string\");\n }\n\n logger.info(\"[RLM Test] Message format test passed\");\n },\n },\n ],\n },\n ],\n};\n\nexport default rlmPlugin;\n\n// Re-export types and client\nexport { configFromEnv, RLMClient, stubResult } from \"./client\";\nexport type {\n GenerateTextParams,\n RLMConfig,\n RLMInferOptions,\n RLMMessage,\n RLMMetadata,\n RLMResult,\n RLMStatusResponse,\n} from \"./types\";\nexport { DEFAULT_CONFIG, ENV_VARS } from \"./types\";\n","/** RLM Client - communicates with Python subprocess via JSON-RPC IPC. */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\n\nimport { assertRecordedLlmCall } from \"@elizaos/core\";\nimport type {\n IPCReadyMessage,\n IPCRequest,\n IPCResponse,\n MetricsCallback,\n RLMConfig,\n RLMInferOptions,\n RLMMessage,\n RLMMetrics,\n RLMResult,\n RLMStatusResponse,\n} from \"./types\";\nimport { DEFAULT_CONFIG, ENV_VARS, validateConfig } from \"./types\";\n\nexport type { MetricsCallback, RLMMetrics };\nexport { DEFAULT_CONFIG };\n\ninterface Logger {\n info: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n debug: (message: string, ...args: unknown[]) => void;\n}\n\nconst defaultLogger: Logger = {\n info: (msg, ...args) => console.log(`[RLM] ${msg}`, ...args),\n warn: (msg, ...args) => console.warn(`[RLM] ${msg}`, ...args),\n error: (msg, ...args) => console.error(`[RLM] ${msg}`, ...args),\n debug: (msg, ...args) => console.debug(`[RLM] ${msg}`, ...args),\n};\n\nexport function configFromEnv(env: NodeJS.ProcessEnv = process.env): RLMConfig {\n return {\n backend: (env[ENV_VARS.BACKEND] as RLMConfig[\"backend\"]) ?? DEFAULT_CONFIG.backend,\n backendKwargs: {},\n environment:\n (env[ENV_VARS.ENVIRONMENT] as RLMConfig[\"environment\"]) ?? DEFAULT_CONFIG.environment,\n maxIterations:\n Number.parseInt(env[ENV_VARS.MAX_ITERATIONS] ?? \"\", 10) || DEFAULT_CONFIG.maxIterations,\n maxDepth: Number.parseInt(env[ENV_VARS.MAX_DEPTH] ?? \"\", 10) || DEFAULT_CONFIG.maxDepth,\n verbose: [\"1\", \"true\", \"yes\"].includes((env[ENV_VARS.VERBOSE] ?? \"\").toLowerCase()),\n pythonPath: env[ENV_VARS.PYTHON_PATH] ?? DEFAULT_CONFIG.pythonPath,\n maxRetries: Number.parseInt(env[ENV_VARS.MAX_RETRIES] ?? \"\", 10) || DEFAULT_CONFIG.maxRetries,\n retryBaseDelay:\n Number.parseInt(env[ENV_VARS.RETRY_BASE_DELAY] ?? \"\", 10) || DEFAULT_CONFIG.retryBaseDelay,\n retryMaxDelay:\n Number.parseInt(env[ENV_VARS.RETRY_MAX_DELAY] ?? \"\", 10) || DEFAULT_CONFIG.retryMaxDelay,\n };\n}\n\nexport class RLMClient {\n private config: RLMConfig;\n private process: ChildProcess | null = null;\n private reader: readline.Interface | null = null;\n private requestId = 0;\n private pendingRequests = new Map<\n number,\n { resolve: (value: IPCResponse) => void; reject: (error: Error) => void }\n >();\n private isReady = false;\n private isAvailable = false;\n private hasStartupError = false;\n private logger: Logger;\n private metrics: RLMMetrics = {\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n stubResponses: 0,\n totalRetries: 0,\n averageLatencyMs: 0,\n p95LatencyMs: 0,\n lastRequestTimestamp: 0,\n };\n private static readonly MAX_LATENCY_SAMPLES = 1000;\n private latencies: number[] = new Array(RLMClient.MAX_LATENCY_SAMPLES).fill(0);\n private latencyIndex = 0;\n private latencyCount = 0;\n private metricsCallback: MetricsCallback | null = null;\n\n constructor(config?: Partial<RLMConfig>, logger?: Logger, strictValidation = false) {\n this.config = { ...configFromEnv(), ...config };\n this.logger = logger ?? defaultLogger;\n\n const errors = validateConfig(this.config);\n if (errors.length > 0) {\n if (strictValidation) {\n throw new Error(`RLM configuration invalid: ${errors.join(\"; \")}`);\n }\n for (const error of errors) {\n this.logger.warn(`Configuration warning: ${error}`);\n }\n }\n }\n\n private async startServer(): Promise<void> {\n if (this.process) return;\n this.hasStartupError = false;\n\n this.logger.debug(\n `Starting RLM server: ${this.config.pythonPath} -m elizaos_plugin_rlm.server`,\n );\n\n try {\n this.process = spawn(this.config.pythonPath, [\"-m\", \"elizaos_plugin_rlm.server\"], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n [ENV_VARS.BACKEND]: this.config.backend,\n [ENV_VARS.ENVIRONMENT]: this.config.environment,\n [ENV_VARS.MAX_ITERATIONS]: String(this.config.maxIterations),\n [ENV_VARS.MAX_DEPTH]: String(this.config.maxDepth),\n [ENV_VARS.VERBOSE]: this.config.verbose ? \"true\" : \"false\",\n },\n cwd: path.join(__dirname, \"..\", \"python\"),\n });\n } catch (error) {\n this.logger.warn(`Failed to start RLM server: ${error}`);\n this.isAvailable = false;\n return;\n }\n\n if (!this.process.stdout || !this.process.stdin) {\n this.logger.warn(\"RLM server process missing stdio streams\");\n this.isAvailable = false;\n return;\n }\n\n // Set up line reader for responses\n this.reader = readline.createInterface({\n input: this.process.stdout,\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n\n // Handle incoming messages\n this.reader.on(\"line\", (line: string) => {\n this.handleMessage(line);\n });\n\n // Handle errors\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n this.logger.debug(`RLM server stderr: ${data.toString()}`);\n });\n\n this.process.on(\"error\", (error: Error) => {\n this.logger.error(`RLM server error: ${error.message}`);\n this.isAvailable = false;\n this.hasStartupError = true;\n });\n\n this.process.on(\"exit\", (code: number | null) => {\n this.logger.debug(`RLM server exited with code ${code}`);\n this.isReady = false;\n this.isAvailable = false;\n this.process = null;\n });\n\n await this.waitForReady();\n }\n\n private waitForReady(): Promise<void> {\n return new Promise((resolve, reject) => {\n const TIMEOUT_MS = 10000;\n const POLL_INTERVAL_MS = 100;\n const deadline = Date.now() + TIMEOUT_MS;\n\n const checkReady = () => {\n if (this.isReady) {\n resolve();\n } else if (!this.process || this.hasStartupError) {\n reject(new Error(\"RLM server process failed before ready\"));\n } else if (Date.now() > deadline) {\n reject(new Error(\"RLM server startup timeout\"));\n } else {\n setTimeout(checkReady, POLL_INTERVAL_MS);\n }\n };\n checkReady();\n });\n }\n\n private handleMessage(line: string): void {\n try {\n const message = JSON.parse(line) as IPCResponse | IPCReadyMessage;\n\n // Check for ready message\n if (\"ready\" in message) {\n const readyMsg = message as IPCReadyMessage;\n this.isReady = true;\n this.isAvailable = readyMsg.available;\n this.logger.info(`RLM server ready, available: ${this.isAvailable}`);\n return;\n }\n\n // Handle response\n const response = message as IPCResponse;\n const pending = this.pendingRequests.get(response.id);\n if (pending) {\n this.pendingRequests.delete(response.id);\n pending.resolve(response);\n }\n } catch (_error) {\n this.logger.error(`Failed to parse RLM server message: ${line}`);\n }\n }\n\n private async sendRequest<T>(\n method: IPCRequest[\"method\"],\n params: Record<string, unknown> = {},\n ): Promise<T> {\n await this.ensureServer();\n\n if (!this.process?.stdin) {\n throw new Error(\"RLM server not running\");\n }\n\n const id = ++this.requestId;\n const request: IPCRequest = { id, method, params };\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`RLM request timeout: ${method}`));\n }, 60000);\n\n this.pendingRequests.set(id, {\n resolve: (response: IPCResponse) => {\n clearTimeout(timeout);\n if (response.error) {\n reject(new Error(response.error));\n } else {\n resolve(response.result as T);\n }\n },\n reject: (error: Error) => {\n clearTimeout(timeout);\n reject(error);\n },\n });\n\n this.process?.stdin?.write(`${JSON.stringify(request)}\\n`);\n });\n }\n\n private async ensureServer(): Promise<void> {\n if (!this.process || !this.isReady) {\n await this.startServer();\n }\n }\n\n get available(): boolean {\n return this.isAvailable;\n }\n\n getMetrics(): RLMMetrics {\n return { ...this.metrics };\n }\n\n onMetrics(callback: MetricsCallback): void {\n this.metricsCallback = callback;\n }\n\n private updateMetrics(\n latencyMs: number,\n success: boolean,\n isStub: boolean,\n error?: string,\n ): void {\n this.metrics.totalRequests++;\n this.metrics.lastRequestTimestamp = Date.now();\n\n if (isStub) {\n this.metrics.stubResponses++;\n } else if (success) {\n this.metrics.successfulRequests++;\n } else {\n this.metrics.failedRequests++;\n this.metrics.lastErrorTimestamp = Date.now();\n this.metrics.lastError = error;\n }\n\n // Track latency in circular buffer\n this.latencies[this.latencyIndex] = latencyMs;\n this.latencyIndex = (this.latencyIndex + 1) % RLMClient.MAX_LATENCY_SAMPLES;\n this.latencyCount = Math.min(this.latencyCount + 1, RLMClient.MAX_LATENCY_SAMPLES);\n\n // Calculate stats from valid samples\n if (this.latencyCount > 0) {\n const valid = this.latencies.slice(0, this.latencyCount);\n this.metrics.averageLatencyMs = valid.reduce((a, b) => a + b, 0) / this.latencyCount;\n this.metrics.p95LatencyMs =\n [...valid].sort((a, b) => a - b)[Math.floor(valid.length * 0.95)] ?? 0;\n }\n\n this.metricsCallback?.(this.getMetrics());\n }\n\n static normalizeMessages(messages: string | RLMMessage[]): RLMMessage[] {\n return typeof messages === \"string\" ? [{ role: \"user\", content: messages }] : messages;\n }\n\n async infer(messages: string | RLMMessage[], opts?: RLMInferOptions): Promise<RLMResult> {\n assertRecordedLlmCall({\n actionType: \"rlm.client.infer\",\n model: opts?.rootModel,\n purpose: \"external_llm\",\n });\n\n const startTime = Date.now();\n const { maxRetries = 3, retryBaseDelay = 1000, retryMaxDelay = 30000 } = this.config;\n const RETRYABLE_PATTERNS = [\"timeout\", \"rate limit\", \"connection\", \"503\", \"429\", \"econnreset\"];\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n await this.ensureServer();\n\n if (!this.isReady) {\n this.updateMetrics(Date.now() - startTime, true, true);\n return stubResult();\n }\n\n const result = await this.sendRequest<RLMResult>(\"infer\", {\n messages: RLMClient.normalizeMessages(messages),\n opts: opts ?? {},\n });\n\n this.updateMetrics(Date.now() - startTime, true, false);\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n const isRetryable = RETRYABLE_PATTERNS.some((p) =>\n lastError?.message.toLowerCase().includes(p),\n );\n\n if (!isRetryable || attempt === maxRetries - 1) {\n this.logger.error(`RLM inference failed after ${attempt + 1} attempts: ${error}`);\n this.updateMetrics(Date.now() - startTime, true, true, lastError.message);\n return stubResult(lastError.message);\n }\n\n const delay =\n Math.min(retryBaseDelay * 2 ** attempt, retryMaxDelay) * (0.75 + Math.random() * 0.5);\n this.metrics.totalRetries++;\n this.logger.warn(\n `RLM attempt ${attempt + 1}/${maxRetries} failed. Retrying in ${Math.round(delay)}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n this.updateMetrics(Date.now() - startTime, false, false, lastError?.message);\n return stubResult(lastError?.message);\n }\n\n async getStatus(): Promise<RLMStatusResponse> {\n try {\n await this.ensureServer();\n return await this.sendRequest<RLMStatusResponse>(\"status\");\n } catch {\n return {\n available: false,\n backend: this.config.backend,\n environment: this.config.environment,\n maxIterations: this.config.maxIterations,\n maxDepth: this.config.maxDepth,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n if (!this.process) return;\n try {\n await this.sendRequest(\"shutdown\");\n } catch {\n /* ignore */\n }\n this.reader?.close();\n this.process?.kill();\n this.process = null;\n this.isReady = false;\n this.isAvailable = false;\n }\n}\n\nexport function stubResult(error?: string): RLMResult {\n return {\n text: \"[RLM STUB] RLM backend not available\",\n metadata: { stub: true, error },\n };\n}\n","/** Types for the RLM (Recursive Language Model) plugin. */\n\nexport type RLMBackend = \"openai\" | \"anthropic\" | \"gemini\" | \"groq\" | \"openrouter\";\nexport type RLMEnvironment = \"local\" | \"docker\" | \"modal\" | \"prime\";\n\nexport interface RLMConfig {\n backend: RLMBackend;\n backendKwargs: Record<string, string>;\n environment: RLMEnvironment;\n maxIterations: number;\n maxDepth: number;\n verbose: boolean;\n pythonPath: string;\n maxRetries?: number;\n retryBaseDelay?: number;\n retryMaxDelay?: number;\n}\n\nexport interface RLMMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n}\n\nexport interface RLMMetadata {\n stub: boolean;\n iterations?: number;\n depth?: number;\n error?: string;\n}\n\nexport interface RLMResult {\n text: string;\n metadata: RLMMetadata;\n}\n\nexport interface RLMInferOptions {\n /** Model identifier for this request */\n model?: string;\n /** Maximum tokens to generate */\n maxTokens?: number;\n /** Sampling temperature */\n temperature?: number;\n /** Top-p sampling parameter */\n topP?: number;\n /** Stop sequences */\n stopSequences?: string[];\n /** User identifier for tracking */\n user?: string;\n /** Enable streaming (not yet supported by RLM) */\n stream?: boolean;\n\n // Per-request RLM overrides (Paper Algorithm 1)\n /** Override max iterations for this request */\n maxIterations?: number;\n /** Override max recursion depth for this request */\n maxDepth?: number;\n /** Override root model for this request */\n rootModel?: string;\n /** Override subcall model for this request */\n subcallModel?: string;\n /** Enable trajectory logging for this request */\n logTrajectories?: boolean;\n /** Enable cost tracking for this request */\n trackCosts?: boolean;\n\n // NOTE: Custom REPL tool injection is NOT supported by the upstream RLM library.\n // See: https://arxiv.org/abs/2512.24601 Section 3.3 - the paper describes the concept\n // but the current library implementation does not expose this capability.\n}\n\nexport interface RLMStatusResponse {\n available: boolean;\n backend: string;\n environment: string;\n maxIterations: number;\n maxDepth: number;\n}\n\nexport interface IPCRequest {\n id: number;\n method: \"infer\" | \"status\" | \"shutdown\";\n params: Record<string, unknown>;\n}\n\nexport interface IPCResponse<T = unknown> {\n id: number;\n result?: T;\n error?: string;\n}\n\nexport interface IPCReadyMessage {\n ready: boolean;\n available: boolean;\n}\n\nexport interface GenerateTextParams {\n prompt?: string;\n system?: string;\n messages?: RLMMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n topP?: number;\n stopSequences?: string[];\n user?: string;\n stream?: boolean;\n}\n\nexport const DEFAULT_CONFIG: RLMConfig = {\n backend: \"gemini\",\n backendKwargs: {},\n environment: \"local\",\n maxIterations: 4,\n maxDepth: 1,\n verbose: false,\n pythonPath: \"python\",\n maxRetries: 3,\n retryBaseDelay: 1000,\n retryMaxDelay: 30000,\n};\n\nexport interface RLMMetrics {\n totalRequests: number;\n successfulRequests: number;\n failedRequests: number;\n stubResponses: number;\n totalRetries: number;\n averageLatencyMs: number;\n p95LatencyMs: number;\n lastRequestTimestamp: number;\n lastErrorTimestamp?: number;\n lastError?: string;\n}\n\nexport type MetricsCallback = (metrics: RLMMetrics) => void;\n\nexport const ENV_VARS = {\n BACKEND: \"ELIZA_RLM_BACKEND\",\n ENVIRONMENT: \"ELIZA_RLM_ENV\",\n MAX_ITERATIONS: \"ELIZA_RLM_MAX_ITERATIONS\",\n MAX_DEPTH: \"ELIZA_RLM_MAX_DEPTH\",\n VERBOSE: \"ELIZA_RLM_VERBOSE\",\n PYTHON_PATH: \"ELIZA_RLM_PYTHON_PATH\",\n MAX_RETRIES: \"ELIZA_RLM_MAX_RETRIES\",\n RETRY_BASE_DELAY: \"ELIZA_RLM_RETRY_BASE_DELAY\",\n RETRY_MAX_DELAY: \"ELIZA_RLM_RETRY_MAX_DELAY\",\n} as const;\n\nexport const VALID_BACKENDS: readonly RLMBackend[] = [\n \"openai\",\n \"anthropic\",\n \"gemini\",\n \"groq\",\n \"openrouter\",\n];\nexport const VALID_ENVIRONMENTS: readonly RLMEnvironment[] = [\"local\", \"docker\", \"modal\", \"prime\"];\n\nexport class RLMConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RLMConfigError\";\n }\n}\n\n/** Validate config. Returns errors array, or throws if strict=true. */\nexport function validateConfig(config: Partial<RLMConfig>, strict = false): string[] {\n const errors: string[] = [];\n\n if (config.backend !== undefined && !VALID_BACKENDS.includes(config.backend)) {\n errors.push(`Invalid backend '${config.backend}'. Valid options: ${VALID_BACKENDS.join(\", \")}`);\n }\n\n if (config.environment !== undefined && !VALID_ENVIRONMENTS.includes(config.environment)) {\n errors.push(\n `Invalid environment '${config.environment}'. Valid options: ${VALID_ENVIRONMENTS.join(\", \")}`,\n );\n }\n\n if (config.maxIterations !== undefined && config.maxIterations < 1) {\n errors.push(\"maxIterations must be >= 1\");\n }\n\n if (config.maxDepth !== undefined && config.maxDepth < 1) {\n errors.push(\"maxDepth must be >= 1\");\n }\n\n if (config.maxRetries !== undefined && config.maxRetries < 0) {\n errors.push(\"maxRetries must be >= 0\");\n }\n\n if (config.retryBaseDelay !== undefined && config.retryBaseDelay < 0) {\n errors.push(\"retryBaseDelay must be >= 0\");\n }\n\n if (\n config.retryBaseDelay !== undefined &&\n config.retryMaxDelay !== undefined &&\n config.retryMaxDelay < config.retryBaseDelay\n ) {\n errors.push(\"retryMaxDelay must be >= retryBaseDelay\");\n }\n\n if (strict && errors.length > 0) {\n throw new RLMConfigError(errors.join(\"; \"));\n }\n\n return errors;\n}\n","/**\n * Cost estimation for RLM inference.\n *\n * Provides model pricing data and cost estimation utilities matching\n * the Python implementation (client.py).\n *\n * Pricing is per 1M tokens (USD). Override via ELIZA_RLM_PRICING_JSON env var.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Cost per 1M tokens for a model. */\nexport interface ModelPricingEntry {\n /** Cost per 1M input tokens (USD). */\n input: number;\n /** Cost per 1M output tokens (USD). */\n output: number;\n}\n\n/** Result of a cost estimation. */\nexport interface CostEstimate {\n /** Model name. */\n model: string;\n /** Backend name (openai, anthropic, gemini, groq). */\n backend: string;\n /** Number of input tokens. */\n inputTokens: number;\n /** Number of output tokens. */\n outputTokens: number;\n /** Cost for input tokens (USD). */\n inputCostUsd: number;\n /** Cost for output tokens (USD). */\n outputCostUsd: number;\n /** Total cost (USD). */\n totalCostUsd: number;\n}\n\ntype PricingTable = Record<string, Record<string, ModelPricingEntry>>;\n\n// ============================================================================\n// Pricing Data — matches Python MODEL_PRICING in client.py\n// ============================================================================\n\n/**\n * Default model pricing per 1M tokens (USD).\n *\n * Organized by backend → model → {input, output}.\n * Matches the Python MODEL_PRICING dictionary exactly.\n */\nexport const MODEL_PRICING: PricingTable = {\n openai: {\n \"gpt-5\": { input: 2.5, output: 10.0 },\n \"gpt-5-preview\": { input: 10.0, output: 30.0 },\n \"gpt-5-mini\": { input: 0.15, output: 0.6 },\n \"gpt-3.5-turbo\": { input: 0.5, output: 1.5 },\n },\n anthropic: {\n \"claude-3-5-sonnet-20241022\": { input: 3.0, output: 15.0 },\n \"claude-3-5-haiku-20241022\": { input: 0.8, output: 4.0 },\n \"claude-3-opus-20240229\": { input: 15.0, output: 75.0 },\n \"claude-3-sonnet-20240229\": { input: 3.0, output: 15.0 },\n \"claude-3-haiku-20240307\": { input: 0.25, output: 1.25 },\n },\n gemini: {\n \"gemini-2.0-flash-exp\": { input: 0.0, output: 0.0 },\n \"gemini-2.0-flash\": { input: 0.075, output: 0.3 },\n \"gemini-1.5-flash\": { input: 0.075, output: 0.3 },\n \"gemini-1.5-pro\": { input: 1.25, output: 5.0 },\n },\n groq: {\n \"openai/gpt-oss-120b\": { input: 0.5, output: 0.8 },\n },\n};\n\n/** Fallback pricing when model is not found in the table. */\nexport const DEFAULT_PRICING: ModelPricingEntry = { input: 1.0, output: 3.0 };\n\n// ============================================================================\n// Pricing Management\n// ============================================================================\n\n/**\n * Set or override pricing for a model (costs per 1M tokens USD).\n *\n * Matches Python `set_model_pricing()`.\n */\nexport function setModelPricing(\n backend: string,\n model: string,\n inputCost: number,\n outputCost: number,\n): void {\n if (!MODEL_PRICING[backend]) {\n MODEL_PRICING[backend] = {};\n }\n MODEL_PRICING[backend][model] = { input: inputCost, output: outputCost };\n}\n\n/**\n * Load custom pricing from ELIZA_RLM_PRICING_JSON environment variable.\n *\n * JSON format: `{ \"backend\": { \"model\": { \"input\": X, \"output\": Y } } }`\n *\n * Matches Python `load_pricing_from_env()`.\n */\nexport function loadPricingFromEnv(): void {\n const env: Record<string, string | undefined> = typeof process !== \"undefined\" ? process.env : {};\n const pricingJson = env.ELIZA_RLM_PRICING_JSON;\n if (!pricingJson) return;\n\n try {\n const customPricing = JSON.parse(pricingJson) as PricingTable;\n for (const [backend, models] of Object.entries(customPricing)) {\n for (const [model, prices] of Object.entries(models)) {\n setModelPricing(backend, model, prices.input ?? 1.0, prices.output ?? 3.0);\n }\n }\n } catch (e) {\n console.warn(`[RLM] Failed to parse ELIZA_RLM_PRICING_JSON: ${e}`);\n }\n}\n\n// Load custom pricing on module import\nloadPricingFromEnv();\n\n// ============================================================================\n// Cost Estimation Functions\n// ============================================================================\n\n/**\n * Estimate API cost in USD based on token counts.\n *\n * Looks up pricing for the given model. If `backend` is provided, searches\n * only that backend; otherwise searches all backends. Falls back to\n * DEFAULT_PRICING if the model is not found.\n *\n * Matches Python `estimate_cost()`.\n *\n * @param model - Model identifier (e.g. \"gpt-5\", \"claude-3-opus-20240229\")\n * @param inputTokens - Number of input tokens\n * @param outputTokens - Number of output tokens\n * @param backend - Optional backend to restrict search (e.g. \"openai\")\n * @returns CostEstimate with computed costs\n */\nexport function estimateCost(\n model: string,\n inputTokens: number,\n outputTokens: number,\n backend?: string,\n): CostEstimate {\n let pricing: ModelPricingEntry | undefined;\n let resolvedBackend = backend ?? \"\";\n\n if (backend) {\n pricing = MODEL_PRICING[backend]?.[model];\n } else {\n // Search all backends for the model\n for (const [b, models] of Object.entries(MODEL_PRICING)) {\n if (models[model]) {\n pricing = models[model];\n resolvedBackend = b;\n break;\n }\n }\n }\n\n if (!pricing) {\n pricing = DEFAULT_PRICING;\n }\n\n const inputCostUsd = (inputTokens / 1_000_000) * pricing.input;\n const outputCostUsd = (outputTokens / 1_000_000) * pricing.output;\n\n return {\n model,\n backend: resolvedBackend,\n inputTokens,\n outputTokens,\n inputCostUsd,\n outputCostUsd,\n totalCostUsd: inputCostUsd + outputCostUsd,\n };\n}\n\n/**\n * Estimate token count for a text string.\n *\n * Uses a len/4 approximation (~4 characters per token). This matches\n * the Python fallback when tiktoken is not available.\n *\n * Matches Python `estimate_token_count()`.\n *\n * @param text - Input text to estimate tokens for\n * @returns Estimated number of tokens\n */\nexport function estimateTokenCount(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Detect RLM strategy from generated code.\n *\n * Strategies (from Paper Section 4.1):\n * - **peek**: Examining prefix/suffix of the prompt (`[:=`, `[:-`, `prompt[`)\n * - **grep**: Regex filtering (`re.search`, `re.findall`, `grep`)\n * - **chunk**: Splitting for parallel processing (`split(`, `partition(`, `chunk`)\n * - **stitch**: Combining sub-call results (`join(`, `concat`, `+=`)\n * - **subcall**: Recursive self-call (`rlm(`, `completion(`, `subcall`)\n * - **other**: Unclassified strategy\n *\n * Matches Python `detect_strategy()`.\n *\n * @param code - Code string to classify\n * @returns Strategy name\n */\nexport function detectStrategy(code: string): string {\n const c = code.toLowerCase();\n\n if (code.includes(\"[:=\") || code.includes(\"[:-\") || c.includes(\"prompt[\")) {\n return \"peek\";\n }\n if ([\"re.search\", \"re.findall\", \"grep\"].some((p) => c.includes(p))) {\n return \"grep\";\n }\n if ([\"split(\", \"partition(\", \"chunk\"].some((p) => c.includes(p))) {\n return \"chunk\";\n }\n if (c.includes(\"join(\") || c.includes(\"concat\") || code.includes(\"+=\")) {\n return \"stitch\";\n }\n if ([\"rlm(\", \"completion(\", \"subcall\"].some((p) => c.includes(p))) {\n return \"subcall\";\n }\n return \"other\";\n}\n"],"mappings":"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","names":["env","logger","env"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-rlm",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
4
|
"description": "RLM (Recursive Language Model) plugin for elizaOS - enables processing of arbitrarily long contexts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsup",
|
|
20
20
|
"dev": "tsup --watch",
|
|
21
|
-
"test": "vitest run --config vitest.config.ts
|
|
21
|
+
"test": "vitest run --config vitest.config.ts",
|
|
22
22
|
"test:watch": "vitest",
|
|
23
23
|
"lint": "bunx @biomejs/biome check --write --unsafe .",
|
|
24
24
|
"lint:fix": "biome check --write .",
|
|
@@ -41,25 +41,25 @@
|
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|
|
43
43
|
"url": "git+https://github.com/elizaos/eliza.git",
|
|
44
|
-
"directory": "plugins/plugin-rlm
|
|
44
|
+
"directory": "plugins/plugin-rlm"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@elizaos/core": "2.0.0-
|
|
47
|
+
"@elizaos/core": "2.0.0-beta.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "^
|
|
51
|
-
"@types/node": "^22.
|
|
52
|
-
"tsup": "^8.
|
|
53
|
-
"typescript": "^
|
|
54
|
-
"vitest": "^
|
|
50
|
+
"@biomejs/biome": "^2.4.14",
|
|
51
|
+
"@types/node": "^22.19.17",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"vitest": "^4.0.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@elizaos/core": "2.0.0-
|
|
57
|
+
"@elizaos/core": "2.0.0-beta.1"
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|
|
60
|
-
"node": ">=
|
|
60
|
+
"node": ">=24.0.0"
|
|
61
61
|
},
|
|
62
|
-
"
|
|
62
|
+
"eliza": {
|
|
63
63
|
"platforms": [
|
|
64
64
|
"node"
|
|
65
65
|
],
|