recursive-llm-ts 5.1.1 → 5.2.4
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 +59 -23
- package/dist/{bridge-factory.js → cjs/bridge-factory.js} +25 -1
- package/dist/{go-bridge.js → cjs/go-bridge.js} +35 -3
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/pkg-dir.d.ts +7 -0
- package/dist/cjs/pkg-dir.js +79 -0
- package/dist/esm/bridge-factory.d.ts +7 -0
- package/dist/esm/bridge-factory.js +60 -0
- package/dist/esm/bridge-interface.d.ts +269 -0
- package/dist/esm/bridge-interface.js +1 -0
- package/dist/esm/cache.d.ts +78 -0
- package/dist/esm/cache.js +207 -0
- package/dist/esm/config.d.ts +37 -0
- package/dist/esm/config.js +152 -0
- package/dist/esm/coordinator.d.ts +17 -0
- package/dist/esm/coordinator.js +41 -0
- package/dist/esm/errors.d.ts +113 -0
- package/dist/esm/errors.js +205 -0
- package/dist/esm/events.d.ts +126 -0
- package/dist/esm/events.js +73 -0
- package/dist/esm/file-storage.d.ts +122 -0
- package/dist/esm/file-storage.js +656 -0
- package/dist/esm/go-bridge.d.ts +5 -0
- package/dist/esm/go-bridge.js +133 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +17 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pkg-dir.d.ts +7 -0
- package/dist/esm/pkg-dir.js +43 -0
- package/dist/esm/retry.d.ts +56 -0
- package/dist/esm/retry.js +181 -0
- package/dist/esm/rlm.d.ts +435 -0
- package/dist/esm/rlm.js +1122 -0
- package/dist/esm/streaming.d.ts +96 -0
- package/dist/esm/streaming.js +205 -0
- package/dist/esm/structured-types.d.ts +28 -0
- package/dist/esm/structured-types.js +1 -0
- package/package.json +20 -8
- package/scripts/build-go-binary.js +26 -0
- /package/dist/{bridge-factory.d.ts → cjs/bridge-factory.d.ts} +0 -0
- /package/dist/{bridge-interface.d.ts → cjs/bridge-interface.d.ts} +0 -0
- /package/dist/{bridge-interface.js → cjs/bridge-interface.js} +0 -0
- /package/dist/{cache.d.ts → cjs/cache.d.ts} +0 -0
- /package/dist/{cache.js → cjs/cache.js} +0 -0
- /package/dist/{config.d.ts → cjs/config.d.ts} +0 -0
- /package/dist/{config.js → cjs/config.js} +0 -0
- /package/dist/{coordinator.d.ts → cjs/coordinator.d.ts} +0 -0
- /package/dist/{coordinator.js → cjs/coordinator.js} +0 -0
- /package/dist/{errors.d.ts → cjs/errors.d.ts} +0 -0
- /package/dist/{errors.js → cjs/errors.js} +0 -0
- /package/dist/{events.d.ts → cjs/events.d.ts} +0 -0
- /package/dist/{events.js → cjs/events.js} +0 -0
- /package/dist/{file-storage.d.ts → cjs/file-storage.d.ts} +0 -0
- /package/dist/{file-storage.js → cjs/file-storage.js} +0 -0
- /package/dist/{go-bridge.d.ts → cjs/go-bridge.d.ts} +0 -0
- /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
- /package/dist/{index.js → cjs/index.js} +0 -0
- /package/dist/{retry.d.ts → cjs/retry.d.ts} +0 -0
- /package/dist/{retry.js → cjs/retry.js} +0 -0
- /package/dist/{rlm.d.ts → cjs/rlm.d.ts} +0 -0
- /package/dist/{rlm.js → cjs/rlm.js} +0 -0
- /package/dist/{streaming.d.ts → cjs/streaming.d.ts} +0 -0
- /package/dist/{streaming.js → cjs/streaming.js} +0 -0
- /package/dist/{structured-types.d.ts → cjs/structured-types.d.ts} +0 -0
- /package/dist/{structured-types.js → cjs/structured-types.js} +0 -0
package/README.md
CHANGED
|
@@ -45,10 +45,30 @@ npm install recursive-llm-ts
|
|
|
45
45
|
### Prerequisites
|
|
46
46
|
|
|
47
47
|
- **Node.js 16+**
|
|
48
|
-
- **Go 1.25+** (
|
|
49
|
-
### Go Binary (Automatic)
|
|
48
|
+
- **Go 1.25+** (only if you need to build the Go binary from source)
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
### Go Binary Resolution
|
|
51
|
+
|
|
52
|
+
On supported platforms, npm installs a matching pre-built binary package automatically:
|
|
53
|
+
|
|
54
|
+
- `@recursive-llm/darwin-arm64`
|
|
55
|
+
- `@recursive-llm/darwin-x64`
|
|
56
|
+
- `@recursive-llm/linux-x64`
|
|
57
|
+
- `@recursive-llm/linux-arm64`
|
|
58
|
+
- `@recursive-llm/win32-x64`
|
|
59
|
+
|
|
60
|
+
This is the default path for most Linux containers, so Go is usually not required in container images.
|
|
61
|
+
|
|
62
|
+
The bridge resolves the binary in this order:
|
|
63
|
+
|
|
64
|
+
1. `config.go_binary_path`
|
|
65
|
+
2. `RLM_GO_BINARY`
|
|
66
|
+
3. Matching `@recursive-llm/<platform>` package
|
|
67
|
+
4. Local `bin/rlm-go` or `go/rlm-go`
|
|
68
|
+
|
|
69
|
+
### Go Binary (Automatic Fallback)
|
|
70
|
+
|
|
71
|
+
When no matching pre-built binary is available, the `postinstall` script attempts to build the Go binary during installation. If Go is not available, the script will warn but not fail.
|
|
52
72
|
|
|
53
73
|
If you need to build manually:
|
|
54
74
|
|
|
@@ -1012,36 +1032,50 @@ See the [LiteLLM documentation](https://docs.litellm.ai/docs/providers) for the
|
|
|
1012
1032
|
|
|
1013
1033
|
## Docker Deployment
|
|
1014
1034
|
|
|
1015
|
-
###
|
|
1035
|
+
### Option 1: Use the Published Linux Binary Package
|
|
1016
1036
|
|
|
1017
|
-
|
|
1037
|
+
On `linux-x64` and `linux-arm64`, `npm ci --omit=dev` installs the matching `@recursive-llm/linux-*` package automatically. This is the simplest container setup and does not require Go or `RLM_GO_BINARY`.
|
|
1018
1038
|
|
|
1019
1039
|
```dockerfile
|
|
1020
|
-
FROM node:
|
|
1040
|
+
FROM node:22-alpine
|
|
1041
|
+
WORKDIR /app
|
|
1021
1042
|
|
|
1022
|
-
|
|
1023
|
-
RUN
|
|
1043
|
+
COPY package*.json ./
|
|
1044
|
+
RUN npm ci --omit=dev
|
|
1024
1045
|
|
|
1025
|
-
|
|
1026
|
-
ENV GOPATH=/go
|
|
1027
|
-
ENV PATH=$PATH:$GOPATH/bin
|
|
1046
|
+
COPY . .
|
|
1028
1047
|
|
|
1048
|
+
ENV OPENAI_API_KEY=""
|
|
1049
|
+
ENV NODE_ENV=production
|
|
1050
|
+
|
|
1051
|
+
CMD ["node", "your-app.js"]
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
### Option 2: Copy or Mount a Custom Binary
|
|
1055
|
+
|
|
1056
|
+
Use this when you build the Go binary elsewhere and want to point the package at an explicit path.
|
|
1057
|
+
|
|
1058
|
+
```dockerfile
|
|
1059
|
+
FROM node:22-alpine
|
|
1029
1060
|
WORKDIR /app
|
|
1030
1061
|
|
|
1031
1062
|
COPY package*.json ./
|
|
1032
|
-
RUN npm
|
|
1063
|
+
RUN npm ci --omit=dev --ignore-scripts
|
|
1033
1064
|
|
|
1034
1065
|
COPY . .
|
|
1066
|
+
COPY ./bin/rlm-go /app/bin/rlm-go
|
|
1067
|
+
RUN chmod +x /app/bin/rlm-go
|
|
1035
1068
|
|
|
1036
1069
|
ENV OPENAI_API_KEY=""
|
|
1037
1070
|
ENV NODE_ENV=production
|
|
1071
|
+
ENV RLM_GO_BINARY=/app/bin/rlm-go
|
|
1038
1072
|
|
|
1039
1073
|
CMD ["node", "your-app.js"]
|
|
1040
1074
|
```
|
|
1041
1075
|
|
|
1042
|
-
###
|
|
1076
|
+
### Option 3: Build from Source in a Multi-Stage Image
|
|
1043
1077
|
|
|
1044
|
-
|
|
1078
|
+
Use this for unsupported targets or when you need a custom-compiled binary.
|
|
1045
1079
|
|
|
1046
1080
|
```dockerfile
|
|
1047
1081
|
# Stage 1: Build the Go binary
|
|
@@ -1053,30 +1087,29 @@ COPY go/ ./
|
|
|
1053
1087
|
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o rlm-go ./cmd/rlm
|
|
1054
1088
|
|
|
1055
1089
|
# Stage 2: Build Node.js dependencies
|
|
1056
|
-
FROM node:
|
|
1090
|
+
FROM node:22-alpine AS node-builder
|
|
1057
1091
|
WORKDIR /app
|
|
1058
1092
|
COPY package*.json ./
|
|
1059
|
-
RUN npm ci --omit=dev
|
|
1093
|
+
RUN npm ci --omit=dev --ignore-scripts
|
|
1060
1094
|
|
|
1061
1095
|
# Stage 3: Final runtime image
|
|
1062
|
-
FROM node:
|
|
1096
|
+
FROM node:22-alpine
|
|
1063
1097
|
WORKDIR /app
|
|
1064
1098
|
|
|
1065
1099
|
COPY --from=node-builder /app/node_modules ./node_modules
|
|
1066
1100
|
COPY --from=go-builder /build/rlm-go ./bin/rlm-go
|
|
1067
1101
|
RUN chmod +x ./bin/rlm-go
|
|
1068
1102
|
|
|
1069
|
-
COPY
|
|
1070
|
-
COPY dist/ ./dist/
|
|
1103
|
+
COPY . .
|
|
1071
1104
|
|
|
1072
1105
|
ENV NODE_ENV=production
|
|
1073
1106
|
ENV RLM_GO_BINARY=/app/bin/rlm-go
|
|
1074
1107
|
ENV OPENAI_API_KEY=""
|
|
1075
1108
|
|
|
1076
|
-
CMD ["node", "
|
|
1109
|
+
CMD ["node", "your-app.js"]
|
|
1077
1110
|
```
|
|
1078
1111
|
|
|
1079
|
-
**Benefits:**
|
|
1112
|
+
**Benefits:** Small runtime image, deterministic binary path, and no Go toolchain in the final image.
|
|
1080
1113
|
|
|
1081
1114
|
### Docker Compose
|
|
1082
1115
|
|
|
@@ -1101,8 +1134,11 @@ RUN apk add --no-cache go
|
|
|
1101
1134
|
# Debian/Ubuntu
|
|
1102
1135
|
RUN apt-get update && apt-get install -y golang-1.25
|
|
1103
1136
|
|
|
1104
|
-
# Or use
|
|
1105
|
-
#
|
|
1137
|
+
# Or use the published platform package (no Go required)
|
|
1138
|
+
# npm ci --omit=dev installs @recursive-llm/linux-x64 or @recursive-llm/linux-arm64 automatically
|
|
1139
|
+
|
|
1140
|
+
# Or use a release binary explicitly
|
|
1141
|
+
# Download from GitHub Releases and set RLM_GO_BINARY=/app/bin/rlm-go
|
|
1106
1142
|
```
|
|
1107
1143
|
|
|
1108
1144
|
## Using the Go Module Directly
|
|
@@ -45,15 +45,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.createBridge = createBridge;
|
|
46
46
|
const fs = __importStar(require("fs"));
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
|
+
const pkg_dir_1 = require("./pkg-dir");
|
|
48
49
|
const DEFAULT_GO_BINARY = process.platform === 'win32' ? 'rlm-go.exe' : 'rlm-go';
|
|
49
50
|
function resolveDefaultGoBinary() {
|
|
50
|
-
return path.join(
|
|
51
|
+
return path.join(pkg_dir_1.PKG_ROOT_DIR, 'bin', DEFAULT_GO_BINARY);
|
|
52
|
+
}
|
|
53
|
+
/** Platform-specific npm package names for pre-built binaries */
|
|
54
|
+
const PLATFORM_PACKAGES = {
|
|
55
|
+
'darwin-arm64': '@recursive-llm/darwin-arm64',
|
|
56
|
+
'darwin-x64': '@recursive-llm/darwin-x64',
|
|
57
|
+
'linux-x64': '@recursive-llm/linux-x64',
|
|
58
|
+
'linux-arm64': '@recursive-llm/linux-arm64',
|
|
59
|
+
'win32-x64': '@recursive-llm/win32-x64',
|
|
60
|
+
};
|
|
61
|
+
function isPlatformBinaryAvailable() {
|
|
62
|
+
const key = `${process.platform}-${process.arch}`;
|
|
63
|
+
const pkgName = PLATFORM_PACKAGES[key];
|
|
64
|
+
if (!pkgName)
|
|
65
|
+
return false;
|
|
66
|
+
try {
|
|
67
|
+
const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
|
|
68
|
+
return fs.existsSync(path.join(pkgDir, 'bin', DEFAULT_GO_BINARY));
|
|
69
|
+
}
|
|
70
|
+
catch (_a) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
51
73
|
}
|
|
52
74
|
function isGoBinaryAvailable() {
|
|
53
75
|
const envPath = process.env.RLM_GO_BINARY;
|
|
54
76
|
if (envPath && fs.existsSync(envPath)) {
|
|
55
77
|
return true;
|
|
56
78
|
}
|
|
79
|
+
if (isPlatformBinaryAvailable())
|
|
80
|
+
return true;
|
|
57
81
|
return fs.existsSync(resolveDefaultGoBinary());
|
|
58
82
|
}
|
|
59
83
|
/**
|
|
@@ -57,16 +57,48 @@ exports.GoBridge = void 0;
|
|
|
57
57
|
const fs = __importStar(require("fs"));
|
|
58
58
|
const path = __importStar(require("path"));
|
|
59
59
|
const child_process_1 = require("child_process");
|
|
60
|
+
const pkg_dir_1 = require("./pkg-dir");
|
|
60
61
|
const DEFAULT_BINARY_NAME = process.platform === 'win32' ? 'rlm-go.exe' : 'rlm-go';
|
|
62
|
+
/** Platform-specific npm package names for pre-built binaries */
|
|
63
|
+
const PLATFORM_PACKAGES = {
|
|
64
|
+
'darwin-arm64': '@recursive-llm/darwin-arm64',
|
|
65
|
+
'darwin-x64': '@recursive-llm/darwin-x64',
|
|
66
|
+
'linux-x64': '@recursive-llm/linux-x64',
|
|
67
|
+
'linux-arm64': '@recursive-llm/linux-arm64',
|
|
68
|
+
'win32-x64': '@recursive-llm/win32-x64',
|
|
69
|
+
};
|
|
70
|
+
function resolvePlatformBinary() {
|
|
71
|
+
const platform = process.platform;
|
|
72
|
+
const arch = process.arch;
|
|
73
|
+
const key = `${platform}-${arch}`;
|
|
74
|
+
const pkgName = PLATFORM_PACKAGES[key];
|
|
75
|
+
if (!pkgName)
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
// require.resolve works in both CJS and ESM (via createRequire)
|
|
79
|
+
const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
|
|
80
|
+
const binPath = path.join(pkgDir, 'bin', DEFAULT_BINARY_NAME);
|
|
81
|
+
if (fs.existsSync(binPath))
|
|
82
|
+
return binPath;
|
|
83
|
+
}
|
|
84
|
+
catch (_a) {
|
|
85
|
+
// Package not installed — fall through
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
61
89
|
function resolveBinaryPath(rlmConfig) {
|
|
62
90
|
const configuredPath = rlmConfig.go_binary_path || process.env.RLM_GO_BINARY;
|
|
63
91
|
if (configuredPath) {
|
|
64
92
|
return configuredPath;
|
|
65
93
|
}
|
|
66
|
-
// Try
|
|
94
|
+
// 1. Try platform-specific npm package (pre-built binary)
|
|
95
|
+
const platformBin = resolvePlatformBinary();
|
|
96
|
+
if (platformBin)
|
|
97
|
+
return platformBin;
|
|
98
|
+
// 2. Try local locations
|
|
67
99
|
const possiblePaths = [
|
|
68
|
-
path.join(
|
|
69
|
-
path.join(
|
|
100
|
+
path.join(pkg_dir_1.PKG_ROOT_DIR, 'bin', DEFAULT_BINARY_NAME), // NPM package (primary)
|
|
101
|
+
path.join(pkg_dir_1.PKG_ROOT_DIR, 'go', DEFAULT_BINARY_NAME), // Development fallback
|
|
70
102
|
];
|
|
71
103
|
for (const p of possiblePaths) {
|
|
72
104
|
if (fs.existsSync(p)) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Directory containing the compiled JS file (dist/cjs or dist/esm or dist) */
|
|
2
|
+
export declare const PKG_DIST_DIR: string;
|
|
3
|
+
/**
|
|
4
|
+
* Package root directory.
|
|
5
|
+
* Handles both flat (dist/) and nested (dist/cjs/, dist/esm/) layouts.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PKG_ROOT_DIR: string;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PKG_ROOT_DIR = exports.PKG_DIST_DIR = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* Portable package directory resolution.
|
|
39
|
+
*
|
|
40
|
+
* Works in both CommonJS and ESM contexts by detecting the available
|
|
41
|
+
* globals and falling back gracefully. The resolved path always points
|
|
42
|
+
* to the package root (parent of the dist/cjs or dist/esm directory).
|
|
43
|
+
*/
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const url_1 = require("url");
|
|
46
|
+
function resolveCurrentDir() {
|
|
47
|
+
// CJS — __dirname is defined natively by Node
|
|
48
|
+
if (typeof __dirname !== 'undefined') {
|
|
49
|
+
return __dirname;
|
|
50
|
+
}
|
|
51
|
+
// ESM — derive from import.meta.url via indirect eval to avoid CJS parse errors.
|
|
52
|
+
// This branch only runs in ESM where import.meta is valid syntax.
|
|
53
|
+
try {
|
|
54
|
+
const meta = new Function('return import.meta')();
|
|
55
|
+
if (meta && typeof meta.url === 'string') {
|
|
56
|
+
return path.dirname((0, url_1.fileURLToPath)(meta.url));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (_a) {
|
|
60
|
+
// Not in ESM or import.meta not supported
|
|
61
|
+
}
|
|
62
|
+
// Last resort: use process.cwd()
|
|
63
|
+
return process.cwd();
|
|
64
|
+
}
|
|
65
|
+
/** Directory containing the compiled JS file (dist/cjs or dist/esm or dist) */
|
|
66
|
+
exports.PKG_DIST_DIR = resolveCurrentDir();
|
|
67
|
+
/**
|
|
68
|
+
* Package root directory.
|
|
69
|
+
* Handles both flat (dist/) and nested (dist/cjs/, dist/esm/) layouts.
|
|
70
|
+
*/
|
|
71
|
+
exports.PKG_ROOT_DIR = (() => {
|
|
72
|
+
const parent = path.dirname(exports.PKG_DIST_DIR);
|
|
73
|
+
const parentBase = path.basename(parent);
|
|
74
|
+
// If parent is 'dist', we're in dist/cjs or dist/esm — go up one more
|
|
75
|
+
if (parentBase === 'dist') {
|
|
76
|
+
return path.dirname(parent);
|
|
77
|
+
}
|
|
78
|
+
return parent;
|
|
79
|
+
})();
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { PKG_ROOT_DIR } from './pkg-dir.js';
|
|
13
|
+
const DEFAULT_GO_BINARY = process.platform === 'win32' ? 'rlm-go.exe' : 'rlm-go';
|
|
14
|
+
function resolveDefaultGoBinary() {
|
|
15
|
+
return path.join(PKG_ROOT_DIR, 'bin', DEFAULT_GO_BINARY);
|
|
16
|
+
}
|
|
17
|
+
/** Platform-specific npm package names for pre-built binaries */
|
|
18
|
+
const PLATFORM_PACKAGES = {
|
|
19
|
+
'darwin-arm64': '@recursive-llm/darwin-arm64',
|
|
20
|
+
'darwin-x64': '@recursive-llm/darwin-x64',
|
|
21
|
+
'linux-x64': '@recursive-llm/linux-x64',
|
|
22
|
+
'linux-arm64': '@recursive-llm/linux-arm64',
|
|
23
|
+
'win32-x64': '@recursive-llm/win32-x64',
|
|
24
|
+
};
|
|
25
|
+
function isPlatformBinaryAvailable() {
|
|
26
|
+
const key = `${process.platform}-${process.arch}`;
|
|
27
|
+
const pkgName = PLATFORM_PACKAGES[key];
|
|
28
|
+
if (!pkgName)
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
|
|
32
|
+
return fs.existsSync(path.join(pkgDir, 'bin', DEFAULT_GO_BINARY));
|
|
33
|
+
}
|
|
34
|
+
catch (_a) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isGoBinaryAvailable() {
|
|
39
|
+
const envPath = process.env.RLM_GO_BINARY;
|
|
40
|
+
if (envPath && fs.existsSync(envPath)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (isPlatformBinaryAvailable())
|
|
44
|
+
return true;
|
|
45
|
+
return fs.existsSync(resolveDefaultGoBinary());
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create the Go bridge for RLM communication.
|
|
49
|
+
* Throws if the Go binary is not available.
|
|
50
|
+
*/
|
|
51
|
+
export function createBridge() {
|
|
52
|
+
return __awaiter(this, arguments, void 0, function* (bridgeType = 'go') {
|
|
53
|
+
if (!isGoBinaryAvailable()) {
|
|
54
|
+
throw new Error('Go RLM binary not found. Build it with: node scripts/build-go-binary.js\n' +
|
|
55
|
+
'Ensure Go 1.25+ is installed: https://go.dev/dl/');
|
|
56
|
+
}
|
|
57
|
+
const { GoBridge } = yield import('./go-bridge.js');
|
|
58
|
+
return new GoBridge();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
export interface RLMStats {
|
|
2
|
+
llm_calls: number;
|
|
3
|
+
iterations: number;
|
|
4
|
+
depth: number;
|
|
5
|
+
parsing_retries?: number;
|
|
6
|
+
total_tokens?: number;
|
|
7
|
+
prompt_tokens?: number;
|
|
8
|
+
completion_tokens?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface RLMResult {
|
|
11
|
+
result: string;
|
|
12
|
+
stats: RLMStats;
|
|
13
|
+
structured_result?: boolean;
|
|
14
|
+
trace_events?: TraceEvent[];
|
|
15
|
+
}
|
|
16
|
+
export interface MetaAgentConfig {
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
model?: string;
|
|
19
|
+
max_optimize_len?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ObservabilityConfig {
|
|
22
|
+
debug?: boolean;
|
|
23
|
+
trace_enabled?: boolean;
|
|
24
|
+
trace_endpoint?: string;
|
|
25
|
+
service_name?: string;
|
|
26
|
+
log_output?: string;
|
|
27
|
+
langfuse_enabled?: boolean;
|
|
28
|
+
langfuse_public_key?: string;
|
|
29
|
+
langfuse_secret_key?: string;
|
|
30
|
+
langfuse_host?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface TraceEvent {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
type: string;
|
|
35
|
+
name: string;
|
|
36
|
+
attributes: Record<string, string>;
|
|
37
|
+
duration?: number;
|
|
38
|
+
trace_id?: string;
|
|
39
|
+
span_id?: string;
|
|
40
|
+
parent_id?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ContextOverflowConfig {
|
|
43
|
+
/** Enable automatic context overflow recovery (default: true) */
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
/** Override detected model token limit (0 = auto-detect from API errors) */
|
|
46
|
+
max_model_tokens?: number;
|
|
47
|
+
/** Strategy: 'mapreduce' (default), 'truncate', 'chunked', 'tfidf', 'textrank', or 'refine' */
|
|
48
|
+
strategy?: 'mapreduce' | 'truncate' | 'chunked' | 'tfidf' | 'textrank' | 'refine';
|
|
49
|
+
/** Fraction of token budget to reserve for prompts/overhead (default: 0.15) */
|
|
50
|
+
safety_margin?: number;
|
|
51
|
+
/** Maximum reduction attempts before giving up (default: 3) */
|
|
52
|
+
max_reduction_attempts?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface LCMConfig {
|
|
55
|
+
/** Enable LCM context management (default: false for backward compat) */
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
/** Soft token threshold — async compaction begins above this (default: 70% of model limit) */
|
|
58
|
+
soft_threshold?: number;
|
|
59
|
+
/** Hard token threshold — blocking compaction above this (default: 90% of model limit) */
|
|
60
|
+
hard_threshold?: number;
|
|
61
|
+
/** Number of messages to compact at once (default: 10) */
|
|
62
|
+
compaction_block_size?: number;
|
|
63
|
+
/** Target tokens per summary node (default: 500) */
|
|
64
|
+
summary_target_tokens?: number;
|
|
65
|
+
/** Large file handling configuration */
|
|
66
|
+
file_handling?: LCMFileConfig;
|
|
67
|
+
/** Episode-based context grouping configuration */
|
|
68
|
+
episodes?: EpisodeConfig;
|
|
69
|
+
/** Persistence backend configuration (default: in-memory) */
|
|
70
|
+
store_backend?: StoreBackendConfig;
|
|
71
|
+
}
|
|
72
|
+
export interface LCMFileConfig {
|
|
73
|
+
/** Token count above which files are stored externally with exploration summaries (default: 25000) */
|
|
74
|
+
token_threshold?: number;
|
|
75
|
+
}
|
|
76
|
+
export interface EpisodeConfig {
|
|
77
|
+
/** Max tokens before auto-closing an episode (default: 2000) */
|
|
78
|
+
max_episode_tokens?: number;
|
|
79
|
+
/** Max messages before auto-closing an episode (default: 20) */
|
|
80
|
+
max_episode_messages?: number;
|
|
81
|
+
/** Topic change sensitivity 0-1 (reserved for future semantic detection) */
|
|
82
|
+
topic_change_threshold?: number;
|
|
83
|
+
/** Auto-generate summary when episode closes (default: true) */
|
|
84
|
+
auto_compact_after_close?: boolean;
|
|
85
|
+
}
|
|
86
|
+
export interface Episode {
|
|
87
|
+
id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
message_ids: string[];
|
|
90
|
+
start_time: string;
|
|
91
|
+
end_time: string;
|
|
92
|
+
tokens: number;
|
|
93
|
+
summary?: string;
|
|
94
|
+
summary_tokens?: number;
|
|
95
|
+
status: 'active' | 'compacted' | 'archived';
|
|
96
|
+
tags?: string[];
|
|
97
|
+
parent_episode_id?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface StoreBackendConfig {
|
|
100
|
+
/** Backend type: 'memory' (default) or 'sqlite' */
|
|
101
|
+
type?: 'memory' | 'sqlite';
|
|
102
|
+
/** Path for SQLite database file (required when type is 'sqlite', use ':memory:' for in-memory SQLite) */
|
|
103
|
+
path?: string;
|
|
104
|
+
}
|
|
105
|
+
export interface LLMMapConfig {
|
|
106
|
+
/** Path to JSONL input file */
|
|
107
|
+
input_path: string;
|
|
108
|
+
/** Path to JSONL output file */
|
|
109
|
+
output_path: string;
|
|
110
|
+
/** Prompt template — use {{item}} as placeholder for each item */
|
|
111
|
+
prompt: string;
|
|
112
|
+
/** JSON Schema for output validation */
|
|
113
|
+
output_schema?: Record<string, any>;
|
|
114
|
+
/** Worker pool concurrency (default: 16) */
|
|
115
|
+
concurrency?: number;
|
|
116
|
+
/** Per-item retry limit (default: 3) */
|
|
117
|
+
max_retries?: number;
|
|
118
|
+
/** Model to use (defaults to engine model) */
|
|
119
|
+
model?: string;
|
|
120
|
+
}
|
|
121
|
+
export interface LLMMapResult {
|
|
122
|
+
total_items: number;
|
|
123
|
+
completed: number;
|
|
124
|
+
failed: number;
|
|
125
|
+
output_path: string;
|
|
126
|
+
duration_ms: number;
|
|
127
|
+
tokens_used: number;
|
|
128
|
+
}
|
|
129
|
+
export interface AgenticMapConfig {
|
|
130
|
+
/** Path to JSONL input file */
|
|
131
|
+
input_path: string;
|
|
132
|
+
/** Path to JSONL output file */
|
|
133
|
+
output_path: string;
|
|
134
|
+
/** Prompt template — use {{item}} as placeholder for each item */
|
|
135
|
+
prompt: string;
|
|
136
|
+
/** JSON Schema for output validation */
|
|
137
|
+
output_schema?: Record<string, any>;
|
|
138
|
+
/** Worker pool concurrency (default: 8) */
|
|
139
|
+
concurrency?: number;
|
|
140
|
+
/** Per-item retry limit (default: 2) */
|
|
141
|
+
max_retries?: number;
|
|
142
|
+
/** Model for sub-agents (defaults to engine model) */
|
|
143
|
+
model?: string;
|
|
144
|
+
/** If true, sub-agents cannot modify filesystem */
|
|
145
|
+
read_only?: boolean;
|
|
146
|
+
/** Max recursion depth for sub-agents (default: 3) */
|
|
147
|
+
max_depth?: number;
|
|
148
|
+
/** Max iterations per sub-agent (default: 15) */
|
|
149
|
+
max_iterations?: number;
|
|
150
|
+
}
|
|
151
|
+
export interface AgenticMapResult {
|
|
152
|
+
total_items: number;
|
|
153
|
+
completed: number;
|
|
154
|
+
failed: number;
|
|
155
|
+
output_path: string;
|
|
156
|
+
duration_ms: number;
|
|
157
|
+
tokens_used: number;
|
|
158
|
+
}
|
|
159
|
+
export interface DelegationRequest {
|
|
160
|
+
/** Task description for the sub-agent */
|
|
161
|
+
prompt: string;
|
|
162
|
+
/** Specific slice of work being handed off (required for non-root) */
|
|
163
|
+
delegated_scope?: string;
|
|
164
|
+
/** Work the caller retains (required for non-root) */
|
|
165
|
+
kept_work?: string;
|
|
166
|
+
/** Read-only exploration agent (exempt from guard) */
|
|
167
|
+
read_only?: boolean;
|
|
168
|
+
/** Parallel decomposition (exempt from guard) */
|
|
169
|
+
parallel?: boolean;
|
|
170
|
+
}
|
|
171
|
+
export interface LCMStoreStats {
|
|
172
|
+
total_messages: number;
|
|
173
|
+
total_summaries: number;
|
|
174
|
+
active_context_items: number;
|
|
175
|
+
active_context_tokens: number;
|
|
176
|
+
immutable_store_tokens: number;
|
|
177
|
+
compression_ratio: number;
|
|
178
|
+
}
|
|
179
|
+
export interface LCMGrepResult {
|
|
180
|
+
message_id: string;
|
|
181
|
+
role: string;
|
|
182
|
+
content: string;
|
|
183
|
+
summary_id?: string;
|
|
184
|
+
match_line: string;
|
|
185
|
+
}
|
|
186
|
+
export interface LCMDescribeResult {
|
|
187
|
+
type: 'message' | 'summary';
|
|
188
|
+
id: string;
|
|
189
|
+
tokens: number;
|
|
190
|
+
role?: string;
|
|
191
|
+
kind?: 'leaf' | 'condensed';
|
|
192
|
+
level?: number;
|
|
193
|
+
covered_ids?: string[];
|
|
194
|
+
file_ids?: string[];
|
|
195
|
+
content?: string;
|
|
196
|
+
}
|
|
197
|
+
export interface EpisodeListResult {
|
|
198
|
+
episodes: Episode[];
|
|
199
|
+
active_episode_id?: string;
|
|
200
|
+
total_episodes: number;
|
|
201
|
+
}
|
|
202
|
+
export interface RLMConfig {
|
|
203
|
+
recursive_model?: string;
|
|
204
|
+
api_base?: string;
|
|
205
|
+
api_key?: string;
|
|
206
|
+
max_depth?: number;
|
|
207
|
+
max_iterations?: number;
|
|
208
|
+
go_binary_path?: string;
|
|
209
|
+
meta_agent?: MetaAgentConfig;
|
|
210
|
+
observability?: ObservabilityConfig;
|
|
211
|
+
context_overflow?: ContextOverflowConfig;
|
|
212
|
+
lcm?: LCMConfig;
|
|
213
|
+
debug?: boolean;
|
|
214
|
+
api_version?: string;
|
|
215
|
+
timeout?: number;
|
|
216
|
+
temperature?: number;
|
|
217
|
+
max_tokens?: number;
|
|
218
|
+
structured?: any;
|
|
219
|
+
[key: string]: any;
|
|
220
|
+
}
|
|
221
|
+
export interface FileStorageConfig {
|
|
222
|
+
/** Storage type: 'local' or 's3' */
|
|
223
|
+
type: 'local' | 's3';
|
|
224
|
+
/** For local: root directory path. For S3: bucket name */
|
|
225
|
+
path: string;
|
|
226
|
+
/** For S3: the prefix (folder path) within the bucket */
|
|
227
|
+
prefix?: string;
|
|
228
|
+
/** For S3: AWS region (falls back to AWS_REGION env var, then 'us-east-1') */
|
|
229
|
+
region?: string;
|
|
230
|
+
/**
|
|
231
|
+
* For S3: explicit credentials.
|
|
232
|
+
* Resolution order:
|
|
233
|
+
* 1. This field (explicit credentials)
|
|
234
|
+
* 2. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
|
|
235
|
+
* 3. AWS SDK default credential chain (IAM role, ~/.aws/credentials, ECS task role, etc.)
|
|
236
|
+
*/
|
|
237
|
+
credentials?: {
|
|
238
|
+
accessKeyId: string;
|
|
239
|
+
secretAccessKey: string;
|
|
240
|
+
sessionToken?: string;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* For S3: custom endpoint URL.
|
|
244
|
+
* Use for S3-compatible services: MinIO, LocalStack, DigitalOcean Spaces, Backblaze B2.
|
|
245
|
+
* When set, forcePathStyle is automatically enabled.
|
|
246
|
+
*/
|
|
247
|
+
endpoint?: string;
|
|
248
|
+
/**
|
|
249
|
+
* For S3: force path-style addressing (bucket in path, not subdomain).
|
|
250
|
+
* Automatically true when endpoint is set.
|
|
251
|
+
*/
|
|
252
|
+
forcePathStyle?: boolean;
|
|
253
|
+
/** Glob patterns to include (e.g. ['*.ts', '*.md']) */
|
|
254
|
+
includePatterns?: string[];
|
|
255
|
+
/** Glob patterns to exclude (e.g. ['node_modules/**']) */
|
|
256
|
+
excludePatterns?: string[];
|
|
257
|
+
/** Maximum file size in bytes to include (default: 1MB) */
|
|
258
|
+
maxFileSize?: number;
|
|
259
|
+
/** Maximum total context size in bytes (default: 10MB) */
|
|
260
|
+
maxTotalSize?: number;
|
|
261
|
+
/** Maximum number of files to include (default: 1000) */
|
|
262
|
+
maxFiles?: number;
|
|
263
|
+
/** File extensions to include (e.g. ['.ts', '.md', '.txt']) */
|
|
264
|
+
extensions?: string[];
|
|
265
|
+
}
|
|
266
|
+
export interface Bridge {
|
|
267
|
+
completion(model: string, query: string, context: string, rlmConfig: RLMConfig): Promise<RLMResult>;
|
|
268
|
+
cleanup(): Promise<void>;
|
|
269
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|