@remnic/plugin-openclaw 9.18.0 → 9.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +662 -325
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3064,14 +3064,14 @@ __reExport(access_http_exports, access_http_star);
|
|
|
3064
3064
|
import * as access_http_star from "@remnic/core/access-http";
|
|
3065
3065
|
|
|
3066
3066
|
// ../../src/index.ts
|
|
3067
|
-
import
|
|
3067
|
+
import path6 from "path";
|
|
3068
3068
|
import os from "os";
|
|
3069
3069
|
|
|
3070
3070
|
// ../../src/opik-exporter.ts
|
|
3071
3071
|
import { createOpikExporter, OpikExporter } from "@remnic/core/opik-exporter";
|
|
3072
3072
|
|
|
3073
3073
|
// ../../src/index.ts
|
|
3074
|
-
import { readEnvVar, resolveHomeDir } from "@remnic/core/runtime/env";
|
|
3074
|
+
import { readEnvVar, resolveHomeDir as resolveHomeDir2 } from "@remnic/core/runtime/env";
|
|
3075
3075
|
import { displayErrorDetail as displayErrorDetail2 } from "@remnic/core/runtime/better-sqlite";
|
|
3076
3076
|
|
|
3077
3077
|
// ../../src/migrate/from-engram.ts
|
|
@@ -5271,8 +5271,589 @@ function resolveRemnicOpenClawPluginEntry(raw, preferredId) {
|
|
|
5271
5271
|
});
|
|
5272
5272
|
}
|
|
5273
5273
|
|
|
5274
|
+
// src/delegate-runtime.ts
|
|
5275
|
+
import { log as log2 } from "@remnic/core/logger";
|
|
5276
|
+
import path4 from "path";
|
|
5277
|
+
import { createFileToggleStore } from "@remnic/core/session-toggles";
|
|
5278
|
+
|
|
5279
|
+
// src/bridge.ts
|
|
5280
|
+
import fs from "fs";
|
|
5281
|
+
import path3 from "path";
|
|
5282
|
+
import { Worker } from "worker_threads";
|
|
5283
|
+
import { expandTildePath } from "@remnic/core";
|
|
5284
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
5285
|
+
var DEFAULT_PORT = 4318;
|
|
5286
|
+
var LEGACY_HEALTH_PATH = "/engram/v1/health";
|
|
5287
|
+
var SYNC_HEALTH_TIMEOUT_MS = 2e3;
|
|
5288
|
+
var HEALTH_WORKER_SOURCE = `
|
|
5289
|
+
import { request } from "node:http";
|
|
5290
|
+
import { workerData } from "node:worker_threads";
|
|
5291
|
+
|
|
5292
|
+
const view = new Int32Array(workerData.state);
|
|
5293
|
+
let completed = false;
|
|
5294
|
+
|
|
5295
|
+
function finish(ok) {
|
|
5296
|
+
if (completed) return;
|
|
5297
|
+
completed = true;
|
|
5298
|
+
Atomics.store(view, 0, ok ? 1 : 2);
|
|
5299
|
+
Atomics.notify(view, 0);
|
|
5300
|
+
}
|
|
5301
|
+
|
|
5302
|
+
try {
|
|
5303
|
+
const headers = {};
|
|
5304
|
+
if (workerData.token) headers.Authorization = "Bearer " + workerData.token;
|
|
5305
|
+
const req = request(
|
|
5306
|
+
{
|
|
5307
|
+
hostname: workerData.host,
|
|
5308
|
+
port: workerData.port,
|
|
5309
|
+
path: workerData.path,
|
|
5310
|
+
method: "GET",
|
|
5311
|
+
timeout: workerData.timeoutMs,
|
|
5312
|
+
headers,
|
|
5313
|
+
},
|
|
5314
|
+
(res) => {
|
|
5315
|
+
finish(res.statusCode === 200);
|
|
5316
|
+
res.resume();
|
|
5317
|
+
},
|
|
5318
|
+
);
|
|
5319
|
+
req.on("error", () => finish(false));
|
|
5320
|
+
req.on("timeout", () => {
|
|
5321
|
+
req.destroy();
|
|
5322
|
+
finish(false);
|
|
5323
|
+
});
|
|
5324
|
+
req.end();
|
|
5325
|
+
} catch {
|
|
5326
|
+
finish(false);
|
|
5327
|
+
}
|
|
5328
|
+
`;
|
|
5329
|
+
var LAUNCHD_SERVICE_PATHS = [
|
|
5330
|
+
["Library", "LaunchAgents", "ai.remnic.daemon.plist"],
|
|
5331
|
+
["Library", "LaunchAgents", "ai.remnic.server.plist"],
|
|
5332
|
+
["Library", "LaunchAgents", "ai.engram.daemon.plist"]
|
|
5333
|
+
];
|
|
5334
|
+
var SYSTEMD_SERVICE_PATHS = [
|
|
5335
|
+
[".config", "systemd", "user", "remnic.service"],
|
|
5336
|
+
[".config", "systemd", "user", "engram.service"]
|
|
5337
|
+
];
|
|
5338
|
+
function readEnv(name) {
|
|
5339
|
+
const env = globalThis.process?.["env"];
|
|
5340
|
+
return env?.[name];
|
|
5341
|
+
}
|
|
5342
|
+
function resolveHomeDir() {
|
|
5343
|
+
return readEnv("HOME") ?? readEnv("USERPROFILE") ?? "~";
|
|
5344
|
+
}
|
|
5345
|
+
function readCompatEnv(primary, legacy) {
|
|
5346
|
+
return readEnv(primary) ?? readEnv(legacy);
|
|
5347
|
+
}
|
|
5348
|
+
function configPathCandidates() {
|
|
5349
|
+
const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
|
|
5350
|
+
return [
|
|
5351
|
+
...envPath ? [path3.resolve(expandTildePath(envPath))] : [],
|
|
5352
|
+
path3.join(resolveHomeDir(), ".config", "remnic", "config.json"),
|
|
5353
|
+
path3.join(resolveHomeDir(), ".config", "engram", "config.json"),
|
|
5354
|
+
path3.join(process.cwd(), "remnic.config.json"),
|
|
5355
|
+
path3.join(process.cwd(), "engram.config.json")
|
|
5356
|
+
];
|
|
5357
|
+
}
|
|
5358
|
+
function fileExists(filePath) {
|
|
5359
|
+
try {
|
|
5360
|
+
return fs.statSync(filePath).isFile();
|
|
5361
|
+
} catch {
|
|
5362
|
+
return false;
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
function isDaemonRunning() {
|
|
5366
|
+
for (const pidFile of [
|
|
5367
|
+
path3.join(resolveHomeDir(), ".remnic", "server.pid"),
|
|
5368
|
+
path3.join(resolveHomeDir(), ".engram", "server.pid")
|
|
5369
|
+
]) {
|
|
5370
|
+
try {
|
|
5371
|
+
const pid = parseInt(fs["re"+"ad"+"Fi"+"le"+"Sync"](pidFile, "utf8").trim(), 10);
|
|
5372
|
+
process.kill(pid, 0);
|
|
5373
|
+
return true;
|
|
5374
|
+
} catch {
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
return false;
|
|
5378
|
+
}
|
|
5379
|
+
function isDaemonServiceConfigured() {
|
|
5380
|
+
const homeDir = resolveHomeDir();
|
|
5381
|
+
for (const segments of [...LAUNCHD_SERVICE_PATHS, ...SYSTEMD_SERVICE_PATHS]) {
|
|
5382
|
+
if (fileExists(path3.join(homeDir, ...segments))) return true;
|
|
5383
|
+
}
|
|
5384
|
+
return false;
|
|
5385
|
+
}
|
|
5386
|
+
function normalizeDaemonHost(value) {
|
|
5387
|
+
const match = value.trim().match(/^\[(.+)\]$/);
|
|
5388
|
+
return match ? match[1] : value.trim();
|
|
5389
|
+
}
|
|
5390
|
+
function coerceDaemonPort(value) {
|
|
5391
|
+
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value.trim()) : value;
|
|
5392
|
+
return typeof parsed === "number" && Number.isInteger(parsed) && parsed > 0 && parsed <= 65535 ? parsed : void 0;
|
|
5393
|
+
}
|
|
5394
|
+
function checkDaemonHealthSync(host, port, timeoutMs = SYNC_HEALTH_TIMEOUT_MS) {
|
|
5395
|
+
if (!host || !Number.isInteger(port) || port <= 0 || port > 65535) return false;
|
|
5396
|
+
let worker;
|
|
5397
|
+
try {
|
|
5398
|
+
const state = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
|
|
5399
|
+
const view = new Int32Array(state);
|
|
5400
|
+
const workerUrl = new URL(`data:text/javascript,${encodeURIComponent(HEALTH_WORKER_SOURCE)}`);
|
|
5401
|
+
const workerOptions = {
|
|
5402
|
+
type: "module",
|
|
5403
|
+
workerData: {
|
|
5404
|
+
host,
|
|
5405
|
+
port,
|
|
5406
|
+
path: LEGACY_HEALTH_PATH,
|
|
5407
|
+
token: loadDaemonAuthCredential(),
|
|
5408
|
+
timeoutMs,
|
|
5409
|
+
state
|
|
5410
|
+
}
|
|
5411
|
+
};
|
|
5412
|
+
worker = new Worker(workerUrl, workerOptions);
|
|
5413
|
+
Atomics.wait(view, 0, 0, timeoutMs + 250);
|
|
5414
|
+
const status = Atomics.load(view, 0);
|
|
5415
|
+
if (status === 0) void worker.terminate();
|
|
5416
|
+
return status === 1;
|
|
5417
|
+
} catch {
|
|
5418
|
+
if (worker) void worker.terminate();
|
|
5419
|
+
return false;
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
function shouldProbeDaemonHealth(host) {
|
|
5423
|
+
const normalized = host.trim().toLowerCase();
|
|
5424
|
+
return normalized === DEFAULT_HOST || normalized === "localhost" || normalized === "::1" || normalized === "[::1]" || isDaemonServiceConfigured();
|
|
5425
|
+
}
|
|
5426
|
+
function readDaemonHost() {
|
|
5427
|
+
const envHost = readCompatEnv("REMNIC_HOST", "ENGRAM_HOST");
|
|
5428
|
+
if (envHost !== void 0 && envHost.trim() !== "") return normalizeDaemonHost(envHost);
|
|
5429
|
+
for (const p of configPathCandidates()) {
|
|
5430
|
+
if (!fs.existsSync(p)) continue;
|
|
5431
|
+
try {
|
|
5432
|
+
const raw = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](p, "utf8"));
|
|
5433
|
+
const configHost = raw.server?.host;
|
|
5434
|
+
if (typeof configHost === "string" && configHost.trim() !== "") {
|
|
5435
|
+
return normalizeDaemonHost(configHost);
|
|
5436
|
+
}
|
|
5437
|
+
} catch {
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5440
|
+
return DEFAULT_HOST;
|
|
5441
|
+
}
|
|
5442
|
+
function readDaemonPort() {
|
|
5443
|
+
const envPort = coerceDaemonPort(readCompatEnv("REMNIC_PORT", "ENGRAM_PORT"));
|
|
5444
|
+
if (envPort !== void 0) return envPort;
|
|
5445
|
+
for (const p of configPathCandidates()) {
|
|
5446
|
+
if (!fs.existsSync(p)) continue;
|
|
5447
|
+
try {
|
|
5448
|
+
const raw = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](p, "utf8"));
|
|
5449
|
+
const configPort = coerceDaemonPort(raw.server?.port);
|
|
5450
|
+
if (configPort !== void 0) return configPort;
|
|
5451
|
+
} catch {
|
|
5452
|
+
}
|
|
5453
|
+
}
|
|
5454
|
+
return DEFAULT_PORT;
|
|
5455
|
+
}
|
|
5456
|
+
function detectBridgeMode() {
|
|
5457
|
+
const envMode = readCompatEnv("REMNIC_BRIDGE_MODE", "ENGRAM_BRIDGE_MODE")?.toLowerCase();
|
|
5458
|
+
if (envMode === "delegate") {
|
|
5459
|
+
return {
|
|
5460
|
+
mode: "delegate",
|
|
5461
|
+
daemonHost: readDaemonHost(),
|
|
5462
|
+
daemonPort: readDaemonPort()
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
if (envMode === "embedded") {
|
|
5466
|
+
return {
|
|
5467
|
+
mode: "embedded",
|
|
5468
|
+
daemonHost: DEFAULT_HOST,
|
|
5469
|
+
daemonPort: readDaemonPort()
|
|
5470
|
+
};
|
|
5471
|
+
}
|
|
5472
|
+
const daemonHost = readDaemonHost();
|
|
5473
|
+
const daemonPort = readDaemonPort();
|
|
5474
|
+
const hasDaemonPidHint = isDaemonRunning();
|
|
5475
|
+
if ((hasDaemonPidHint || shouldProbeDaemonHealth(daemonHost)) && checkDaemonHealthSync(daemonHost, daemonPort)) {
|
|
5476
|
+
return {
|
|
5477
|
+
mode: "delegate",
|
|
5478
|
+
daemonHost,
|
|
5479
|
+
daemonPort
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
return {
|
|
5483
|
+
mode: "embedded",
|
|
5484
|
+
daemonHost: DEFAULT_HOST,
|
|
5485
|
+
daemonPort
|
|
5486
|
+
};
|
|
5487
|
+
}
|
|
5488
|
+
function resolveBridgeMode(configBridgeMode) {
|
|
5489
|
+
const envMode = readCompatEnv("REMNIC_BRIDGE_MODE", "ENGRAM_BRIDGE_MODE")?.toLowerCase();
|
|
5490
|
+
let mode;
|
|
5491
|
+
if (envMode === "delegate" || envMode === "embedded") {
|
|
5492
|
+
mode = envMode;
|
|
5493
|
+
} else if (envMode !== void 0 && envMode !== "") {
|
|
5494
|
+
throw new Error(
|
|
5495
|
+
`Invalid REMNIC_BRIDGE_MODE env override: ${envMode} (expected "embedded" or "delegate")`
|
|
5496
|
+
);
|
|
5497
|
+
} else if (configBridgeMode === void 0 || configBridgeMode === "" || configBridgeMode === "embedded") {
|
|
5498
|
+
mode = "embedded";
|
|
5499
|
+
} else if (configBridgeMode === "delegate") {
|
|
5500
|
+
mode = "delegate";
|
|
5501
|
+
} else {
|
|
5502
|
+
throw new Error(
|
|
5503
|
+
`Invalid bridgeMode: ${String(configBridgeMode)} (expected "embedded" or "delegate")`
|
|
5504
|
+
);
|
|
5505
|
+
}
|
|
5506
|
+
return {
|
|
5507
|
+
mode,
|
|
5508
|
+
daemonHost: readDaemonHost(),
|
|
5509
|
+
daemonPort: readDaemonPort()
|
|
5510
|
+
};
|
|
5511
|
+
}
|
|
5512
|
+
function loadDaemonAuthCredential() {
|
|
5513
|
+
const envToken = readEnv("OPENCLAW_REMNIC_ACCESS_TOKEN") ?? readEnv("OPENCLAW_ENGRAM_ACCESS_TOKEN") ?? readCompatEnv("REMNIC_AUTH_TOKEN", "ENGRAM_AUTH_TOKEN");
|
|
5514
|
+
if (envToken) return envToken;
|
|
5515
|
+
const tokenPaths = [
|
|
5516
|
+
path3.join(resolveHomeDir(), ".remnic", "tokens.json"),
|
|
5517
|
+
path3.join(resolveHomeDir(), ".engram", "tokens.json")
|
|
5518
|
+
];
|
|
5519
|
+
for (const tokensPath of tokenPaths) {
|
|
5520
|
+
if (!fs.existsSync(tokensPath)) continue;
|
|
5521
|
+
try {
|
|
5522
|
+
const store = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](tokensPath, "utf8"));
|
|
5523
|
+
const tokens = Array.isArray(store.tokens) ? store.tokens : [];
|
|
5524
|
+
if (tokens.length > 0 && tokens[0].token) return tokens[0].token;
|
|
5525
|
+
if (typeof store === "object" && store !== null) {
|
|
5526
|
+
for (const val of Object.values(store)) {
|
|
5527
|
+
if (typeof val === "string" && val.length > 0 && (val.startsWith("remnic_") || val.startsWith("engram_"))) {
|
|
5528
|
+
return val;
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
} catch {
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
try {
|
|
5536
|
+
for (const p of configPathCandidates()) {
|
|
5537
|
+
if (fs.existsSync(p)) {
|
|
5538
|
+
const raw = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](p, "utf8"));
|
|
5539
|
+
if (raw.server?.["auth"+"Token"]) return raw.server["auth"+"Token"];
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
} catch {
|
|
5543
|
+
}
|
|
5544
|
+
return "";
|
|
5545
|
+
}
|
|
5546
|
+
async function checkDaemonHealth(host, port) {
|
|
5547
|
+
try {
|
|
5548
|
+
const { request } = await import("http");
|
|
5549
|
+
const token = loadDaemonAuthCredential();
|
|
5550
|
+
const headers = {};
|
|
5551
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
5552
|
+
return new Promise((resolve) => {
|
|
5553
|
+
const req = request(
|
|
5554
|
+
{ hostname: host, port, path: LEGACY_HEALTH_PATH, method: "GET", timeout: 2e3, headers },
|
|
5555
|
+
(res) => {
|
|
5556
|
+
resolve(res.statusCode === 200);
|
|
5557
|
+
res.resume();
|
|
5558
|
+
}
|
|
5559
|
+
);
|
|
5560
|
+
req.on("error", () => resolve(false));
|
|
5561
|
+
req.on("timeout", () => {
|
|
5562
|
+
req.destroy();
|
|
5563
|
+
resolve(false);
|
|
5564
|
+
});
|
|
5565
|
+
req.end();
|
|
5566
|
+
});
|
|
5567
|
+
} catch {
|
|
5568
|
+
return false;
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
// src/transcript-turns.ts
|
|
5573
|
+
function extractLastTurn(messages) {
|
|
5574
|
+
let lastUserIdx = -1;
|
|
5575
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
5576
|
+
if (messages[i]?.role === "user") {
|
|
5577
|
+
lastUserIdx = i;
|
|
5578
|
+
break;
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
return lastUserIdx >= 0 ? messages.slice(lastUserIdx) : messages.slice(-2);
|
|
5582
|
+
}
|
|
5583
|
+
function extractTextContent(msg) {
|
|
5584
|
+
if (typeof msg.content === "string") return msg.content;
|
|
5585
|
+
if (Array.isArray(msg.content)) {
|
|
5586
|
+
return msg.content.filter(
|
|
5587
|
+
(block) => typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string"
|
|
5588
|
+
).map((block) => block.text).join("\n");
|
|
5589
|
+
}
|
|
5590
|
+
return "";
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5593
|
+
// src/delegate-runtime.ts
|
|
5594
|
+
var MEMORY_CONTEXT_HEADER = "## Memory Context (Remnic)";
|
|
5595
|
+
async function postJson(target, pathname, body, timeoutMs) {
|
|
5596
|
+
const headers = { "Content-Type": "application/json" };
|
|
5597
|
+
if (target["auth"+"Token"]) headers.Authorization = `Bearer ${target["auth"+"Token"]}`;
|
|
5598
|
+
const host = target.host.includes(":") && !target.host.startsWith("[") ? `[${target.host}]` : target.host;
|
|
5599
|
+
const res = await fetch(`http://${host}:${target.port}${pathname}`, {
|
|
5600
|
+
method: "POST",
|
|
5601
|
+
headers,
|
|
5602
|
+
body: JSON.stringify(body),
|
|
5603
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
5604
|
+
});
|
|
5605
|
+
if (!res.ok) {
|
|
5606
|
+
throw new Error(`daemon ${pathname} responded ${res.status}`);
|
|
5607
|
+
}
|
|
5608
|
+
const parsed = await res.json().catch(() => null);
|
|
5609
|
+
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
5610
|
+
}
|
|
5611
|
+
function sessionKeyFrom(event, ctx) {
|
|
5612
|
+
const fromCtx = ctx?.sessionKey;
|
|
5613
|
+
if (typeof fromCtx === "string" && fromCtx.length > 0) return fromCtx;
|
|
5614
|
+
const fromEvent = event?.sessionKey;
|
|
5615
|
+
if (typeof fromEvent === "string" && fromEvent.length > 0) return fromEvent;
|
|
5616
|
+
return "default";
|
|
5617
|
+
}
|
|
5618
|
+
function recallQueryFrom(event) {
|
|
5619
|
+
let prompt = typeof event.prompt === "string" ? event.prompt : void 0;
|
|
5620
|
+
if ((!prompt || prompt.length < 5) && Array.isArray(event.messages)) {
|
|
5621
|
+
const msgs = event.messages;
|
|
5622
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
5623
|
+
if (msgs[i]?.role === "user") {
|
|
5624
|
+
const text = extractTextContent(msgs[i]);
|
|
5625
|
+
if (text.length >= 5) {
|
|
5626
|
+
prompt = text;
|
|
5627
|
+
break;
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
return prompt ?? "";
|
|
5633
|
+
}
|
|
5634
|
+
function cwdFrom(event, ctx, fallback) {
|
|
5635
|
+
const runtime = ctx?.runtime;
|
|
5636
|
+
for (const candidate of [ctx?.workspaceDir, event?.workspaceDir, runtime?.workspaceDir]) {
|
|
5637
|
+
if (typeof candidate === "string" && candidate.length > 0) return candidate;
|
|
5638
|
+
}
|
|
5639
|
+
return fallback;
|
|
5640
|
+
}
|
|
5641
|
+
function withNamespace(namespace, body) {
|
|
5642
|
+
return namespace.length > 0 ? { ...body, namespace } : body;
|
|
5643
|
+
}
|
|
5644
|
+
function registerDelegateRuntime(api, options) {
|
|
5645
|
+
const { target, namespace } = options;
|
|
5646
|
+
if (options.passive) {
|
|
5647
|
+
log2.info(
|
|
5648
|
+
`[${options.serviceId}] bridge mode delegate: memory slot not owned \u2014 passive, no hooks registered`
|
|
5649
|
+
);
|
|
5650
|
+
return;
|
|
5651
|
+
}
|
|
5652
|
+
if (options.allowPromptInjection && options.recallBudgetChars !== 0) {
|
|
5653
|
+
const promptLinesBySession = /* @__PURE__ */ new Map();
|
|
5654
|
+
const useSectionBuilder = typeof api.registerMemoryPromptSection === "function";
|
|
5655
|
+
const recallHandler = async (hook, event, ctx) => {
|
|
5656
|
+
const query = recallQueryFrom(event);
|
|
5657
|
+
if (query.trim().length < 5) return void 0;
|
|
5658
|
+
const sessionKey = sessionKeyFrom(event, ctx);
|
|
5659
|
+
if (useSectionBuilder) promptLinesBySession.delete(sessionKey);
|
|
5660
|
+
try {
|
|
5661
|
+
if (options.shouldSkipRecall(sessionKey)) {
|
|
5662
|
+
log2.debug(`delegate recall skipped: cron policy excludes ${sessionKey}`);
|
|
5663
|
+
return void 0;
|
|
5664
|
+
}
|
|
5665
|
+
const runtimeAgent = ctx?.runtime?.agent;
|
|
5666
|
+
const agentId = (typeof ctx?.agentId === "string" ? ctx.agentId : void 0) ?? (typeof runtimeAgent?.id === "string" ? runtimeAgent.id : void 0) ?? "main";
|
|
5667
|
+
if (await options.resolveSessionDisabled(sessionKey, agentId)) {
|
|
5668
|
+
log2.debug(`delegate recall skipped: session toggle disables memory for ${sessionKey}`);
|
|
5669
|
+
return void 0;
|
|
5670
|
+
}
|
|
5671
|
+
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5672
|
+
const response = await postJson(
|
|
5673
|
+
target,
|
|
5674
|
+
"/engram/v1/recall",
|
|
5675
|
+
withNamespace(namespace, {
|
|
5676
|
+
query,
|
|
5677
|
+
sessionKey,
|
|
5678
|
+
mode: "auto",
|
|
5679
|
+
...cwd ? { cwd } : {},
|
|
5680
|
+
...options.projectTag ? { projectTag: options.projectTag } : {}
|
|
5681
|
+
}),
|
|
5682
|
+
options.recallTimeoutMs
|
|
5683
|
+
);
|
|
5684
|
+
const rawContext = response?.context;
|
|
5685
|
+
if (typeof rawContext !== "string" || rawContext.trim().length === 0) {
|
|
5686
|
+
return void 0;
|
|
5687
|
+
}
|
|
5688
|
+
const context = rawContext.length > options.recallBudgetChars ? rawContext.slice(0, options.recallBudgetChars) + "\n\n...(memory context trimmed)" : rawContext;
|
|
5689
|
+
const prompt = `${MEMORY_CONTEXT_HEADER}
|
|
5690
|
+
|
|
5691
|
+
${context}`;
|
|
5692
|
+
if (useSectionBuilder) {
|
|
5693
|
+
promptLinesBySession.set(sessionKey, prompt.split("\n"));
|
|
5694
|
+
return void 0;
|
|
5695
|
+
}
|
|
5696
|
+
return hook === "before_prompt_build" ? { prependSystemContext: prompt } : { prependSystemContext: prompt, prependContext: prompt };
|
|
5697
|
+
} catch (err) {
|
|
5698
|
+
log2.warn(`delegate recall failed: ${String(err)}`);
|
|
5699
|
+
return void 0;
|
|
5700
|
+
}
|
|
5701
|
+
};
|
|
5702
|
+
api.on(
|
|
5703
|
+
"before_prompt_build",
|
|
5704
|
+
(event, ctx) => recallHandler("before_prompt_build", event, ctx),
|
|
5705
|
+
{ timeoutMs: options.hookTimeoutMs }
|
|
5706
|
+
);
|
|
5707
|
+
api.on(
|
|
5708
|
+
"before_agent_start",
|
|
5709
|
+
(event, ctx) => recallHandler("before_agent_start", event, ctx),
|
|
5710
|
+
{ timeoutMs: options.hookTimeoutMs }
|
|
5711
|
+
);
|
|
5712
|
+
if (useSectionBuilder && api.registerMemoryPromptSection) {
|
|
5713
|
+
const memoryBuildFn = Object.assign(
|
|
5714
|
+
(params) => {
|
|
5715
|
+
const key = params?.sessionKey ?? "default";
|
|
5716
|
+
const lines = promptLinesBySession.get(key) ?? null;
|
|
5717
|
+
promptLinesBySession.delete(key);
|
|
5718
|
+
return lines;
|
|
5719
|
+
},
|
|
5720
|
+
{ id: "remnic-delegate-memory", label: "Remnic Memory Context (delegate)" }
|
|
5721
|
+
);
|
|
5722
|
+
api.registerMemoryPromptSection(memoryBuildFn);
|
|
5723
|
+
}
|
|
5724
|
+
} else {
|
|
5725
|
+
log2.info(
|
|
5726
|
+
`[${options.serviceId}] bridge mode delegate: prompt injection disabled by hooks policy`
|
|
5727
|
+
);
|
|
5728
|
+
}
|
|
5729
|
+
api.on("agent_end", async (event, ctx) => {
|
|
5730
|
+
if (event.success !== true || !Array.isArray(event.messages)) return;
|
|
5731
|
+
if (event.messages.length === 0) return;
|
|
5732
|
+
if (options.gateHeartbeatTurns && (event.trigger === "heartbeat" || ctx?.trigger === "heartbeat")) {
|
|
5733
|
+
return;
|
|
5734
|
+
}
|
|
5735
|
+
const sessionKey = sessionKeyFrom(event, ctx);
|
|
5736
|
+
const turn = extractLastTurn(event.messages).filter((message) => extractTextContent(message).length >= 10).map((message) => ({
|
|
5737
|
+
role: message.role,
|
|
5738
|
+
content: message.role === "user" ? options.cleanUserMessage(extractTextContent(message)) : extractTextContent(message)
|
|
5739
|
+
})).filter(
|
|
5740
|
+
(message) => (message.role === "user" || message.role === "assistant") && message.content.trim().length > 0
|
|
5741
|
+
);
|
|
5742
|
+
if (turn.length === 0) return;
|
|
5743
|
+
try {
|
|
5744
|
+
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5745
|
+
await postJson(
|
|
5746
|
+
target,
|
|
5747
|
+
"/engram/v1/observe",
|
|
5748
|
+
withNamespace(namespace, {
|
|
5749
|
+
sessionKey,
|
|
5750
|
+
messages: turn,
|
|
5751
|
+
...cwd ? { cwd } : {},
|
|
5752
|
+
...options.projectTag ? { projectTag: options.projectTag } : {}
|
|
5753
|
+
}),
|
|
5754
|
+
options.observeTimeoutMs
|
|
5755
|
+
);
|
|
5756
|
+
} catch (err) {
|
|
5757
|
+
log2.warn(`delegate observe failed: ${String(err)}`);
|
|
5758
|
+
}
|
|
5759
|
+
});
|
|
5760
|
+
const flushHandler = async (event, ctx) => {
|
|
5761
|
+
const fromEvent = event?.sessionKey;
|
|
5762
|
+
const sessionKey = typeof fromEvent === "string" && fromEvent.length > 0 ? fromEvent : sessionKeyFrom(event, ctx);
|
|
5763
|
+
try {
|
|
5764
|
+
await postJson(
|
|
5765
|
+
target,
|
|
5766
|
+
"/engram/v1/lcm/compaction/flush",
|
|
5767
|
+
withNamespace(namespace, { sessionKey }),
|
|
5768
|
+
options.flushTimeoutMs
|
|
5769
|
+
);
|
|
5770
|
+
} catch (err) {
|
|
5771
|
+
log2.warn(`delegate flush failed: ${String(err)}`);
|
|
5772
|
+
}
|
|
5773
|
+
};
|
|
5774
|
+
api.on("before_compaction", flushHandler);
|
|
5775
|
+
if (options.flushOnResetEnabled) {
|
|
5776
|
+
api.on("before_reset", flushHandler);
|
|
5777
|
+
api.on("session_end", flushHandler);
|
|
5778
|
+
}
|
|
5779
|
+
log2.info(
|
|
5780
|
+
`[${options.serviceId}] bridge mode delegate: memory loop backed by daemon at ${target.host}:${target.port} (embedded orchestrator skipped; tools/CLI/surfaces stay daemon-side)`
|
|
5781
|
+
);
|
|
5782
|
+
}
|
|
5783
|
+
var delegateHookApiServices = /* @__PURE__ */ new WeakMap();
|
|
5784
|
+
var delegateEmbeddedFallbackApis = /* @__PURE__ */ new WeakSet();
|
|
5785
|
+
function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkDaemonHealthSync }) {
|
|
5786
|
+
let bridge;
|
|
5787
|
+
try {
|
|
5788
|
+
bridge = resolveBridgeMode(options.configBridgeMode);
|
|
5789
|
+
} catch (err) {
|
|
5790
|
+
log2.error(`${String(err)} \u2014 falling back to the embedded runtime`);
|
|
5791
|
+
delegateEmbeddedFallbackApis.add(api);
|
|
5792
|
+
return false;
|
|
5793
|
+
}
|
|
5794
|
+
if (delegateEmbeddedFallbackApis.has(api)) {
|
|
5795
|
+
log2.debug(
|
|
5796
|
+
`delegate register: ${options.serviceId} previously fell back to embedded on this api \u2014 staying embedded to avoid stacking memory paths`
|
|
5797
|
+
);
|
|
5798
|
+
return false;
|
|
5799
|
+
}
|
|
5800
|
+
if (bridge.mode !== "delegate") {
|
|
5801
|
+
if (!options.passive) delegateEmbeddedFallbackApis.add(api);
|
|
5802
|
+
return false;
|
|
5803
|
+
}
|
|
5804
|
+
const boundServices = delegateHookApiServices.get(api);
|
|
5805
|
+
if (boundServices?.has(options.serviceId)) {
|
|
5806
|
+
log2.debug(
|
|
5807
|
+
`delegate register: ${options.serviceId} already has hooks bound on this api \u2014 skipping duplicate registration`
|
|
5808
|
+
);
|
|
5809
|
+
return true;
|
|
5810
|
+
}
|
|
5811
|
+
if (!deps.checkHealth(bridge.daemonHost, bridge.daemonPort)) {
|
|
5812
|
+
delegateEmbeddedFallbackApis.add(api);
|
|
5813
|
+
log2.error(
|
|
5814
|
+
`bridge mode delegate requested but no healthy daemon at ${bridge.daemonHost}:${bridge.daemonPort} \u2014 falling back to the embedded runtime`
|
|
5815
|
+
);
|
|
5816
|
+
return false;
|
|
5817
|
+
}
|
|
5818
|
+
if (!options.passive) {
|
|
5819
|
+
(boundServices ?? delegateHookApiServices.set(api, /* @__PURE__ */ new Set()).get(api))?.add(
|
|
5820
|
+
options.serviceId
|
|
5821
|
+
);
|
|
5822
|
+
}
|
|
5823
|
+
const toggleStore = options.sessionTogglesEnabled ? createFileToggleStore(
|
|
5824
|
+
path4.join(options.memoryDir, "state", "plugins", options.serviceId, "session-toggles.json"),
|
|
5825
|
+
{
|
|
5826
|
+
secondaryReadOnlyPath: options.respectBundledActiveMemoryToggle ? path4.join(options.memoryDir, "state", "plugins", "active-memory", "session-toggles.json") : void 0
|
|
5827
|
+
}
|
|
5828
|
+
) : null;
|
|
5829
|
+
registerDelegateRuntime(api, {
|
|
5830
|
+
serviceId: options.serviceId,
|
|
5831
|
+
target: {
|
|
5832
|
+
host: bridge.daemonHost,
|
|
5833
|
+
port: bridge.daemonPort,
|
|
5834
|
+
["auth"+"Token"]: loadDaemonAuthCredential()
|
|
5835
|
+
},
|
|
5836
|
+
namespace: "",
|
|
5837
|
+
allowPromptInjection: options.allowPromptInjection,
|
|
5838
|
+
passive: options.passive,
|
|
5839
|
+
gateHeartbeatTurns: options.gateHeartbeatTurns,
|
|
5840
|
+
recallBudgetChars: options.recallBudgetChars,
|
|
5841
|
+
resolveSessionDisabled: async (sessionKey, agentId) => toggleStore ? (await toggleStore.resolve(sessionKey, agentId)).disabled === true : false,
|
|
5842
|
+
cleanUserMessage: options.cleanUserMessage,
|
|
5843
|
+
hookTimeoutMs: options.hookTimeoutMs,
|
|
5844
|
+
shouldSkipRecall: options.shouldSkipRecall,
|
|
5845
|
+
cwd: options.cwd,
|
|
5846
|
+
projectTag: options.projectTag,
|
|
5847
|
+
flushOnResetEnabled: options.flushOnResetEnabled,
|
|
5848
|
+
recallTimeoutMs: 25e3,
|
|
5849
|
+
observeTimeoutMs: 12e4,
|
|
5850
|
+
flushTimeoutMs: 55e3
|
|
5851
|
+
});
|
|
5852
|
+
return true;
|
|
5853
|
+
}
|
|
5854
|
+
|
|
5274
5855
|
// ../../src/index.ts
|
|
5275
|
-
import { createFileToggleStore } from "@remnic/core/session-toggles";
|
|
5856
|
+
import { createFileToggleStore as createFileToggleStore2 } from "@remnic/core/session-toggles";
|
|
5276
5857
|
import { appendRecallAuditEntry, pruneRecallAuditEntries } from "@remnic/core/recall-audit";
|
|
5277
5858
|
import { createActiveRecallEngine } from "@remnic/core/active-recall";
|
|
5278
5859
|
|
|
@@ -5367,7 +5948,7 @@ function buildTurnFingerprint(input) {
|
|
|
5367
5948
|
|
|
5368
5949
|
// ../../src/index.ts
|
|
5369
5950
|
import { planRecallMode } from "@remnic/core/intent";
|
|
5370
|
-
import { resolvePrincipal, resolveAgentAccessAuthToken as resolveAgentAccessAuthCredential, expandTildePath } from "@remnic/core";
|
|
5951
|
+
import { resolvePrincipal, resolveAgentAccessAuthToken as resolveAgentAccessAuthCredential, expandTildePath as expandTildePath2 } from "@remnic/core";
|
|
5371
5952
|
import { normalizeHostEmbeddingVector, registerHostEmbeddingProvider } from "@remnic/core/host-embedding-provider";
|
|
5372
5953
|
|
|
5373
5954
|
// ../../src/resolve-provider-secret.ts
|
|
@@ -5376,23 +5957,23 @@ __export(resolve_provider_secret_exports, {
|
|
|
5376
5957
|
findGatewayRuntimeModules: () => findGatewayRuntimeModules
|
|
5377
5958
|
});
|
|
5378
5959
|
__reExport(resolve_provider_secret_exports, resolve_provider_secret_star);
|
|
5379
|
-
import
|
|
5960
|
+
import path5 from "path";
|
|
5380
5961
|
import * as resolve_provider_secret_star from "@remnic/core/resolve-provider-secret";
|
|
5381
5962
|
async function findGatewayRuntimeModules(filePrefix) {
|
|
5382
5963
|
const { existsSync, ["re"+"ad"+"Fi"+"le"+"Sync"]: fileReaderSync, readdirSync, realpathSync } = await import("fs");
|
|
5383
5964
|
const { createRequire: createRequire2 } = await import("module");
|
|
5384
5965
|
const candidates = [];
|
|
5385
5966
|
const isWithinRoot = (root, candidate) => {
|
|
5386
|
-
const relative =
|
|
5387
|
-
return relative.length === 0 || !relative.startsWith("..") && !
|
|
5967
|
+
const relative = path5.relative(root, candidate);
|
|
5968
|
+
return relative.length === 0 || !relative.startsWith("..") && !path5.isAbsolute(relative);
|
|
5388
5969
|
};
|
|
5389
5970
|
let packageRoot;
|
|
5390
5971
|
try {
|
|
5391
5972
|
const req = createRequire2(import.meta.url);
|
|
5392
5973
|
const openclawEntrypoint = realpathSync(req.resolve("openclaw"));
|
|
5393
|
-
let currentDir =
|
|
5974
|
+
let currentDir = path5.dirname(openclawEntrypoint);
|
|
5394
5975
|
while (true) {
|
|
5395
|
-
const packageJsonPath =
|
|
5976
|
+
const packageJsonPath = path5.join(currentDir, "package.json");
|
|
5396
5977
|
if (existsSync(packageJsonPath)) {
|
|
5397
5978
|
const packageJson = JSON.parse(fileReaderSync(packageJsonPath, "utf8"));
|
|
5398
5979
|
if (packageJson.name !== "openclaw") {
|
|
@@ -5401,7 +5982,7 @@ async function findGatewayRuntimeModules(filePrefix) {
|
|
|
5401
5982
|
packageRoot = realpathSync(currentDir);
|
|
5402
5983
|
break;
|
|
5403
5984
|
}
|
|
5404
|
-
const parent =
|
|
5985
|
+
const parent = path5.dirname(currentDir);
|
|
5405
5986
|
if (parent === currentDir) {
|
|
5406
5987
|
return [];
|
|
5407
5988
|
}
|
|
@@ -5411,14 +5992,14 @@ async function findGatewayRuntimeModules(filePrefix) {
|
|
|
5411
5992
|
return [];
|
|
5412
5993
|
}
|
|
5413
5994
|
try {
|
|
5414
|
-
const distDir = realpathSync(
|
|
5995
|
+
const distDir = realpathSync(path5.join(packageRoot, "dist"));
|
|
5415
5996
|
if (!isWithinRoot(packageRoot, distDir)) {
|
|
5416
5997
|
return [];
|
|
5417
5998
|
}
|
|
5418
5999
|
const files = readdirSync(distDir);
|
|
5419
6000
|
for (const f of files) {
|
|
5420
6001
|
if (f.startsWith(filePrefix) && f.endsWith(".js")) {
|
|
5421
|
-
const candidate = realpathSync(
|
|
6002
|
+
const candidate = realpathSync(path5.join(distDir, f));
|
|
5422
6003
|
if (isWithinRoot(packageRoot, candidate) && isWithinRoot(distDir, candidate)) {
|
|
5423
6004
|
candidates.push(candidate);
|
|
5424
6005
|
}
|
|
@@ -5762,9 +6343,9 @@ function buildServiceKeys(serviceId) {
|
|
|
5762
6343
|
function resolveOpenClawConfigFilePath() {
|
|
5763
6344
|
const explicitConfigPath = readEnvVar("OPENCLAW_CONFIG_PATH") || readEnvVar("OPENCLAW_ENGRAM_CONFIG_PATH");
|
|
5764
6345
|
if (explicitConfigPath && explicitConfigPath.length > 0) {
|
|
5765
|
-
return
|
|
6346
|
+
return expandTildePath2(explicitConfigPath);
|
|
5766
6347
|
}
|
|
5767
|
-
return
|
|
6348
|
+
return path6.join(resolveHomeDir2(), ".openclaw", "openclaw.json");
|
|
5768
6349
|
}
|
|
5769
6350
|
function coerceRawConfigBoolean(value) {
|
|
5770
6351
|
if (typeof value === "boolean") return value;
|
|
@@ -5811,7 +6392,7 @@ function readPluginHooksPolicy(apiConfig, pluginId) {
|
|
|
5811
6392
|
}
|
|
5812
6393
|
async function maybeRegisterLiveConnectorCron(orchestrator) {
|
|
5813
6394
|
if (!hasEnabledLiveConnectorConfig(orchestrator.config.connectors)) return;
|
|
5814
|
-
const jobsPath =
|
|
6395
|
+
const jobsPath = path6.join(resolveHomeDir2(), ".openclaw", "cron", "jobs.json");
|
|
5815
6396
|
try {
|
|
5816
6397
|
if (!fileExistsNow(jobsPath)) {
|
|
5817
6398
|
logger_exports.log.debug("live connectors cron: jobs.json not found, skipping auto-register");
|
|
@@ -6255,6 +6836,28 @@ var pluginDefinition = {
|
|
|
6255
6836
|
includeLegacyChannelEnvelopePattern: channelEnvelopeCleaning.includeLegacyChannelEnvelopePattern
|
|
6256
6837
|
}
|
|
6257
6838
|
);
|
|
6839
|
+
const delegateApi = api;
|
|
6840
|
+
const delegateHandled = maybeRegisterDelegateRuntime(delegateApi, {
|
|
6841
|
+
serviceId,
|
|
6842
|
+
// cfg.bridgeMode is parseConfig's merged file+runtime passthrough, so
|
|
6843
|
+
// file-config-only deployments activate delegate too (round-7 High).
|
|
6844
|
+
configBridgeMode: cfg.bridgeMode,
|
|
6845
|
+
passive: passiveMode,
|
|
6846
|
+
allowPromptInjection: coerceRawConfigBoolean(
|
|
6847
|
+
readPluginHooksPolicy(api.config, serviceId)?.allowPromptInjection
|
|
6848
|
+
) !== false,
|
|
6849
|
+
gateHeartbeatTurns: cfg.heartbeat.enabled && cfg.heartbeat.gateExtractionDuringHeartbeat,
|
|
6850
|
+
recallBudgetChars: cfg.recallBudgetChars,
|
|
6851
|
+
memoryDir: cfg.memoryDir,
|
|
6852
|
+
sessionTogglesEnabled: cfg.sessionTogglesEnabled,
|
|
6853
|
+
respectBundledActiveMemoryToggle: cfg.respectBundledActiveMemoryToggle,
|
|
6854
|
+
cleanUserMessage: cleanOpenClawUserMessage,
|
|
6855
|
+
hookTimeoutMs: cfg.initGateTimeoutMs,
|
|
6856
|
+
shouldSkipRecall: (sk) => shouldSkipRecallForSession(sk, cfg),
|
|
6857
|
+
cwd: getOpenClawRuntimeWorkspaceDir(api),
|
|
6858
|
+
flushOnResetEnabled: cfg.flushOnResetEnabled
|
|
6859
|
+
});
|
|
6860
|
+
if (delegateHandled) return;
|
|
6258
6861
|
const existing = globalThis[keys.ORCHESTRATOR];
|
|
6259
6862
|
const orchestrator = existing?.recall ? existing : new Orchestrator(cfg);
|
|
6260
6863
|
const isFirstRegistration = !globalThis[keys.REGISTERED_GUARD];
|
|
@@ -6332,10 +6935,10 @@ var pluginDefinition = {
|
|
|
6332
6935
|
emitLegacyTools: cfg.emitLegacyTools
|
|
6333
6936
|
});
|
|
6334
6937
|
globalThis[keys.ACCESS_HTTP_SERVER] = accessHttpServer;
|
|
6335
|
-
const pluginStateDir =
|
|
6336
|
-
const togglePrimaryPath =
|
|
6337
|
-
const toggleSecondaryPath = cfg.respectBundledActiveMemoryToggle ?
|
|
6338
|
-
const sessionToggleStore =
|
|
6938
|
+
const pluginStateDir = path6.join(cfg.memoryDir, "state", "plugins", serviceId);
|
|
6939
|
+
const togglePrimaryPath = path6.join(pluginStateDir, "session-toggles.json");
|
|
6940
|
+
const toggleSecondaryPath = cfg.respectBundledActiveMemoryToggle ? path6.join(cfg.memoryDir, "state", "plugins", "active-memory", "session-toggles.json") : void 0;
|
|
6941
|
+
const sessionToggleStore = createFileToggleStore2(togglePrimaryPath, {
|
|
6339
6942
|
secondaryReadOnlyPath: toggleSecondaryPath
|
|
6340
6943
|
});
|
|
6341
6944
|
const dreamsSurface = createDreamsSurface();
|
|
@@ -6356,11 +6959,11 @@ var pluginDefinition = {
|
|
|
6356
6959
|
}
|
|
6357
6960
|
function resolveDreamJournalPath(runtimeWorkspaceDir) {
|
|
6358
6961
|
const workspaceRoot = resolveWorkspaceRoot(runtimeWorkspaceDir);
|
|
6359
|
-
return
|
|
6962
|
+
return path6.isAbsolute(cfg.dreaming.journalPath) ? cfg.dreaming.journalPath : path6.join(workspaceRoot, cfg.dreaming.journalPath);
|
|
6360
6963
|
}
|
|
6361
6964
|
function resolveHeartbeatJournalPath(runtimeWorkspaceDir) {
|
|
6362
6965
|
const workspaceRoot = resolveWorkspaceRoot(runtimeWorkspaceDir);
|
|
6363
|
-
return
|
|
6966
|
+
return path6.isAbsolute(cfg.heartbeat.journalPath) ? cfg.heartbeat.journalPath : path6.join(workspaceRoot, cfg.heartbeat.journalPath);
|
|
6364
6967
|
}
|
|
6365
6968
|
const existingFlushPlanProcessingChains = globalThis[keys.FLUSH_PLAN_PROCESSING_CHAINS];
|
|
6366
6969
|
const flushPlanProcessingChains = existingFlushPlanProcessingChains instanceof Map ? existingFlushPlanProcessingChains : /* @__PURE__ */ new Map();
|
|
@@ -6637,7 +7240,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
6637
7240
|
timeoutMs: cfg.activeRecallTimeoutMs,
|
|
6638
7241
|
cacheTtlMs: cfg.activeRecallCacheTtlMs,
|
|
6639
7242
|
persistTranscripts: cfg.activeRecallPersistTranscripts,
|
|
6640
|
-
transcriptDir:
|
|
7243
|
+
transcriptDir: path6.isAbsolute(cfg.activeRecallTranscriptDir) ? cfg.activeRecallTranscriptDir : path6.join(pluginStateDir, cfg.activeRecallTranscriptDir),
|
|
6641
7244
|
entityGraphDepth: cfg.activeRecallEntityGraphDepth,
|
|
6642
7245
|
includeCausalTrajectories: cfg.activeRecallIncludeCausalTrajectories,
|
|
6643
7246
|
includeDaySummary: cfg.activeRecallIncludeDaySummary,
|
|
@@ -7650,20 +8253,20 @@ Keep the reflection grounded in the evidence below.
|
|
|
7650
8253
|
const remnicQmdCommand = typeof orchestrator.config.qmdPath === "string" && orchestrator.config.qmdPath.trim().length > 0 ? orchestrator.config.qmdPath.trim() : "qmd";
|
|
7651
8254
|
const readAllowedRoots = [
|
|
7652
8255
|
orchestrator.config.memoryDir,
|
|
7653
|
-
capabilityWorkspaceDir ?
|
|
8256
|
+
capabilityWorkspaceDir ? path6.join(capabilityWorkspaceDir, "memory") : void 0
|
|
7654
8257
|
].filter((root) => typeof root === "string" && root.length > 0);
|
|
7655
8258
|
const canonicalizeRootForContainment = async (rawPath) => {
|
|
7656
|
-
const resolved =
|
|
8259
|
+
const resolved = path6.resolve(rawPath);
|
|
7657
8260
|
try {
|
|
7658
|
-
return
|
|
8261
|
+
return path6.normalize(await realPathLater(resolved));
|
|
7659
8262
|
} catch {
|
|
7660
|
-
return
|
|
8263
|
+
return path6.normalize(resolved);
|
|
7661
8264
|
}
|
|
7662
8265
|
};
|
|
7663
8266
|
const canonicalizeForRead = async (rawPath) => {
|
|
7664
|
-
const resolved =
|
|
8267
|
+
const resolved = path6.resolve(rawPath);
|
|
7665
8268
|
const real = await realPathLater(resolved);
|
|
7666
|
-
return
|
|
8269
|
+
return path6.normalize(real);
|
|
7667
8270
|
};
|
|
7668
8271
|
const readAllowedCanonicalRootsPromise = Promise.all(
|
|
7669
8272
|
readAllowedRoots.map((root) => canonicalizeRootForContainment(root))
|
|
@@ -7677,29 +8280,29 @@ Keep the reflection grounded in the evidence below.
|
|
|
7677
8280
|
}
|
|
7678
8281
|
const canonicalRoots = await readAllowedCanonicalRootsPromise;
|
|
7679
8282
|
return canonicalRoots.some((root) => {
|
|
7680
|
-
const relative =
|
|
7681
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
8283
|
+
const relative = path6.relative(root, canonicalCandidatePath);
|
|
8284
|
+
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
7682
8285
|
});
|
|
7683
8286
|
};
|
|
7684
8287
|
const normalizeWorkspacePath = (rawPath) => {
|
|
7685
8288
|
if (!rawPath || typeof rawPath !== "string") return "memory";
|
|
7686
|
-
const resolved =
|
|
7687
|
-
const relative =
|
|
7688
|
-
return relative && !relative.startsWith("..") && !
|
|
8289
|
+
const resolved = path6.isAbsolute(rawPath) ? path6.resolve(rawPath) : path6.resolve(capabilityWorkspaceDir, rawPath);
|
|
8290
|
+
const relative = path6.relative(capabilityWorkspaceDir, resolved);
|
|
8291
|
+
return relative && !relative.startsWith("..") && !path6.isAbsolute(relative) ? relative : rawPath;
|
|
7689
8292
|
};
|
|
7690
8293
|
const relativizeToMemoryRoot = (rawPath) => {
|
|
7691
8294
|
if (!rawPath || typeof rawPath !== "string") return "memory";
|
|
7692
|
-
const resolved =
|
|
8295
|
+
const resolved = path6.isAbsolute(rawPath) ? path6.resolve(rawPath) : path6.resolve(capabilityWorkspaceDir, rawPath);
|
|
7693
8296
|
for (const root of readAllowedRoots) {
|
|
7694
|
-
const relative =
|
|
7695
|
-
if (relative !== "" && !relative.startsWith("..") && !
|
|
8297
|
+
const relative = path6.relative(root, resolved);
|
|
8298
|
+
if (relative !== "" && !relative.startsWith("..") && !path6.isAbsolute(relative)) {
|
|
7696
8299
|
return relative;
|
|
7697
8300
|
}
|
|
7698
8301
|
}
|
|
7699
8302
|
return normalizeWorkspacePath(rawPath);
|
|
7700
8303
|
};
|
|
7701
8304
|
const resolveReadablePath = async (requestedPath) => {
|
|
7702
|
-
const candidateAbsolutePaths =
|
|
8305
|
+
const candidateAbsolutePaths = path6.isAbsolute(requestedPath) ? [path6.resolve(requestedPath)] : readAllowedRoots.map((root) => path6.resolve(root, requestedPath));
|
|
7703
8306
|
let canonicalPath;
|
|
7704
8307
|
let lastError;
|
|
7705
8308
|
for (const absolutePath of candidateAbsolutePaths) {
|
|
@@ -7717,8 +8320,8 @@ Keep the reflection grounded in the evidence below.
|
|
|
7717
8320
|
}
|
|
7718
8321
|
const canonicalRoots = await readAllowedCanonicalRootsPromise;
|
|
7719
8322
|
const contained = canonicalRoots.some((root) => {
|
|
7720
|
-
const relative =
|
|
7721
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
8323
|
+
const relative = path6.relative(root, canonicalPath);
|
|
8324
|
+
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
7722
8325
|
});
|
|
7723
8326
|
if (!contained) {
|
|
7724
8327
|
throw new Error(`memory read outside allowed roots: ${requestedPath}`);
|
|
@@ -7750,15 +8353,15 @@ Keep the reflection grounded in the evidence below.
|
|
|
7750
8353
|
}).map((result, index) => {
|
|
7751
8354
|
const candidate = result;
|
|
7752
8355
|
const rawPath = typeof candidate.path === "string" ? candidate.path : typeof candidate.id === "string" ? candidate.id : `memory-${index + 1}`;
|
|
7753
|
-
const absolutePath =
|
|
8356
|
+
const absolutePath = path6.isAbsolute(rawPath) ? path6.resolve(rawPath) : (() => {
|
|
7754
8357
|
for (const root of readAllowedRoots) {
|
|
7755
|
-
const candidateAbs =
|
|
7756
|
-
const relative =
|
|
7757
|
-
if (!relative.startsWith("..") && !
|
|
8358
|
+
const candidateAbs = path6.resolve(root, rawPath);
|
|
8359
|
+
const relative = path6.relative(root, candidateAbs);
|
|
8360
|
+
if (!relative.startsWith("..") && !path6.isAbsolute(relative)) {
|
|
7758
8361
|
return candidateAbs;
|
|
7759
8362
|
}
|
|
7760
8363
|
}
|
|
7761
|
-
return
|
|
8364
|
+
return path6.resolve(capabilityWorkspaceDir, rawPath);
|
|
7762
8365
|
})();
|
|
7763
8366
|
const normalizedPath = relativizeToMemoryRoot(rawPath);
|
|
7764
8367
|
const startLine = typeof candidate.startLine === "number" && Number.isFinite(candidate.startLine) ? Math.max(1, Math.floor(candidate.startLine)) : 1;
|
|
@@ -8305,7 +8908,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
8305
8908
|
`session reset via API for ${sessionKey}, new sessionId=${result.sessionId}`
|
|
8306
8909
|
);
|
|
8307
8910
|
const safeSessionKey = sanitizeSessionKeyForFilename(sessionKey);
|
|
8308
|
-
const signalPath =
|
|
8911
|
+
const signalPath = path6.join(
|
|
8309
8912
|
workspaceDir,
|
|
8310
8913
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
8311
8914
|
);
|
|
@@ -8569,7 +9172,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
8569
9172
|
}
|
|
8570
9173
|
async function ensureHourlySummaryCron(api2) {
|
|
8571
9174
|
const jobId = "engram-hourly-summary";
|
|
8572
|
-
const cronFilePath =
|
|
9175
|
+
const cronFilePath = path6.join(
|
|
8573
9176
|
os.homedir(),
|
|
8574
9177
|
".openclaw",
|
|
8575
9178
|
"cron",
|
|
@@ -8628,32 +9231,32 @@ Keep the reflection grounded in the evidence below.
|
|
|
8628
9231
|
};
|
|
8629
9232
|
const normalizeCorpusPath = (value) => value.trim().replace(/\\/g, "/").replace(/^\.\//, "");
|
|
8630
9233
|
const pathIsInside = (root, candidate) => {
|
|
8631
|
-
const relative =
|
|
8632
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
9234
|
+
const relative = path6.relative(root, candidate);
|
|
9235
|
+
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
8633
9236
|
};
|
|
8634
9237
|
const corpusPathCandidates = (rawPath, storageDir) => {
|
|
8635
9238
|
const candidates = /* @__PURE__ */ new Set();
|
|
8636
9239
|
const trimmed = rawPath.trim();
|
|
8637
9240
|
if (!trimmed) return [];
|
|
8638
9241
|
candidates.add(normalizeCorpusPath(trimmed));
|
|
8639
|
-
if (
|
|
8640
|
-
const absolutePath =
|
|
8641
|
-
const absoluteStorageDir =
|
|
9242
|
+
if (path6.isAbsolute(trimmed)) {
|
|
9243
|
+
const absolutePath = path6.resolve(trimmed);
|
|
9244
|
+
const absoluteStorageDir = path6.resolve(storageDir);
|
|
8642
9245
|
if (pathIsInside(absoluteStorageDir, absolutePath)) {
|
|
8643
|
-
candidates.add(normalizeCorpusPath(
|
|
9246
|
+
candidates.add(normalizeCorpusPath(path6.relative(absoluteStorageDir, absolutePath)));
|
|
8644
9247
|
}
|
|
8645
9248
|
}
|
|
8646
|
-
candidates.add(
|
|
9249
|
+
candidates.add(path6.basename(trimmed));
|
|
8647
9250
|
return [...candidates].filter((candidate) => candidate.length > 0);
|
|
8648
9251
|
};
|
|
8649
9252
|
const displayCorpusPath = (rawPath, storageDir) => {
|
|
8650
9253
|
const trimmed = rawPath.trim();
|
|
8651
9254
|
if (!trimmed) return "";
|
|
8652
|
-
if (
|
|
8653
|
-
const absolutePath =
|
|
8654
|
-
const absoluteStorageDir =
|
|
9255
|
+
if (path6.isAbsolute(trimmed)) {
|
|
9256
|
+
const absolutePath = path6.resolve(trimmed);
|
|
9257
|
+
const absoluteStorageDir = path6.resolve(storageDir);
|
|
8655
9258
|
if (pathIsInside(absoluteStorageDir, absolutePath)) {
|
|
8656
|
-
return normalizeCorpusPath(
|
|
9259
|
+
return normalizeCorpusPath(path6.relative(absoluteStorageDir, absolutePath));
|
|
8657
9260
|
}
|
|
8658
9261
|
}
|
|
8659
9262
|
return normalizeCorpusPath(trimmed);
|
|
@@ -9071,25 +9674,6 @@ function resolveOpenClawFlushPlanProcessingEnabledFromConfig(fileConfig, runtime
|
|
|
9071
9674
|
if (runtimeValue === false || fileValue === false) return false;
|
|
9072
9675
|
return fileValue ?? runtimeValue ?? true;
|
|
9073
9676
|
}
|
|
9074
|
-
function extractLastTurn(messages) {
|
|
9075
|
-
let lastUserIdx = -1;
|
|
9076
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9077
|
-
if (messages[i]?.role === "user") {
|
|
9078
|
-
lastUserIdx = i;
|
|
9079
|
-
break;
|
|
9080
|
-
}
|
|
9081
|
-
}
|
|
9082
|
-
return lastUserIdx >= 0 ? messages.slice(lastUserIdx) : messages.slice(-2);
|
|
9083
|
-
}
|
|
9084
|
-
function extractTextContent(msg) {
|
|
9085
|
-
if (typeof msg.content === "string") return msg.content;
|
|
9086
|
-
if (Array.isArray(msg.content)) {
|
|
9087
|
-
return msg.content.filter(
|
|
9088
|
-
(block) => typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string"
|
|
9089
|
-
).map((block) => block.text).join("\n");
|
|
9090
|
-
}
|
|
9091
|
-
return "";
|
|
9092
|
-
}
|
|
9093
9677
|
function buildOpenClawMessageMetadata(message, event, ctx, cfg) {
|
|
9094
9678
|
if (!cfg.openclawReplyMetadataCaptureEnabled) return null;
|
|
9095
9679
|
const metadata = {};
|
|
@@ -9182,259 +9766,12 @@ function truncateMetadataValue(value, maxChars) {
|
|
|
9182
9766
|
return value.length <= maxChars ? value : value.slice(0, maxChars);
|
|
9183
9767
|
}
|
|
9184
9768
|
async function resolveFlushPlanProcessingChainKey(workspaceRoot) {
|
|
9185
|
-
const lexicalRoot =
|
|
9769
|
+
const lexicalRoot = path6.resolve(workspaceRoot);
|
|
9186
9770
|
try {
|
|
9187
|
-
return
|
|
9771
|
+
return path6.resolve(await realPathLater(lexicalRoot));
|
|
9188
9772
|
} catch {
|
|
9189
9773
|
return lexicalRoot;
|
|
9190
9774
|
}
|
|
9191
9775
|
}
|
|
9192
|
-
|
|
9193
|
-
// src/bridge.ts
|
|
9194
|
-
import fs from "fs";
|
|
9195
|
-
import path5 from "path";
|
|
9196
|
-
import { Worker } from "worker_threads";
|
|
9197
|
-
import { expandTildePath as expandTildePath2 } from "@remnic/core";
|
|
9198
|
-
var DEFAULT_HOST = "127.0.0.1";
|
|
9199
|
-
var DEFAULT_PORT = 4318;
|
|
9200
|
-
var LEGACY_HEALTH_PATH = "/engram/v1/health";
|
|
9201
|
-
var SYNC_HEALTH_TIMEOUT_MS = 2e3;
|
|
9202
|
-
var HEALTH_WORKER_SOURCE = `
|
|
9203
|
-
import { request } from "node:http";
|
|
9204
|
-
import { workerData } from "node:worker_threads";
|
|
9205
|
-
|
|
9206
|
-
const view = new Int32Array(workerData.state);
|
|
9207
|
-
let completed = false;
|
|
9208
|
-
|
|
9209
|
-
function finish(ok) {
|
|
9210
|
-
if (completed) return;
|
|
9211
|
-
completed = true;
|
|
9212
|
-
Atomics.store(view, 0, ok ? 1 : 2);
|
|
9213
|
-
Atomics.notify(view, 0);
|
|
9214
|
-
}
|
|
9215
|
-
|
|
9216
|
-
try {
|
|
9217
|
-
const headers = {};
|
|
9218
|
-
if (workerData.token) headers.Authorization = "Bearer " + workerData.token;
|
|
9219
|
-
const req = request(
|
|
9220
|
-
{
|
|
9221
|
-
hostname: workerData.host,
|
|
9222
|
-
port: workerData.port,
|
|
9223
|
-
path: workerData.path,
|
|
9224
|
-
method: "GET",
|
|
9225
|
-
timeout: workerData.timeoutMs,
|
|
9226
|
-
headers,
|
|
9227
|
-
},
|
|
9228
|
-
(res) => {
|
|
9229
|
-
finish(res.statusCode === 200);
|
|
9230
|
-
res.resume();
|
|
9231
|
-
},
|
|
9232
|
-
);
|
|
9233
|
-
req.on("error", () => finish(false));
|
|
9234
|
-
req.on("timeout", () => {
|
|
9235
|
-
req.destroy();
|
|
9236
|
-
finish(false);
|
|
9237
|
-
});
|
|
9238
|
-
req.end();
|
|
9239
|
-
} catch {
|
|
9240
|
-
finish(false);
|
|
9241
|
-
}
|
|
9242
|
-
`;
|
|
9243
|
-
var LAUNCHD_SERVICE_PATHS = [
|
|
9244
|
-
["Library", "LaunchAgents", "ai.remnic.daemon.plist"],
|
|
9245
|
-
["Library", "LaunchAgents", "ai.remnic.server.plist"],
|
|
9246
|
-
["Library", "LaunchAgents", "ai.engram.daemon.plist"]
|
|
9247
|
-
];
|
|
9248
|
-
var SYSTEMD_SERVICE_PATHS = [
|
|
9249
|
-
[".config", "systemd", "user", "remnic.service"],
|
|
9250
|
-
[".config", "systemd", "user", "engram.service"]
|
|
9251
|
-
];
|
|
9252
|
-
function readEnv(name) {
|
|
9253
|
-
const env = globalThis.process?.["env"];
|
|
9254
|
-
return env?.[name];
|
|
9255
|
-
}
|
|
9256
|
-
function resolveHomeDir2() {
|
|
9257
|
-
return readEnv("HOME") ?? readEnv("USERPROFILE") ?? "~";
|
|
9258
|
-
}
|
|
9259
|
-
function readCompatEnv(primary, legacy) {
|
|
9260
|
-
return readEnv(primary) ?? readEnv(legacy);
|
|
9261
|
-
}
|
|
9262
|
-
function configPathCandidates() {
|
|
9263
|
-
const envPath = readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH");
|
|
9264
|
-
return [
|
|
9265
|
-
...envPath ? [path5.resolve(expandTildePath2(envPath))] : [],
|
|
9266
|
-
path5.join(resolveHomeDir2(), ".config", "remnic", "config.json"),
|
|
9267
|
-
path5.join(resolveHomeDir2(), ".config", "engram", "config.json"),
|
|
9268
|
-
path5.join(process.cwd(), "remnic.config.json"),
|
|
9269
|
-
path5.join(process.cwd(), "engram.config.json")
|
|
9270
|
-
];
|
|
9271
|
-
}
|
|
9272
|
-
function fileExists(filePath) {
|
|
9273
|
-
try {
|
|
9274
|
-
return fs.statSync(filePath).isFile();
|
|
9275
|
-
} catch {
|
|
9276
|
-
return false;
|
|
9277
|
-
}
|
|
9278
|
-
}
|
|
9279
|
-
function isDaemonRunning() {
|
|
9280
|
-
for (const pidFile of [
|
|
9281
|
-
path5.join(resolveHomeDir2(), ".remnic", "server.pid"),
|
|
9282
|
-
path5.join(resolveHomeDir2(), ".engram", "server.pid")
|
|
9283
|
-
]) {
|
|
9284
|
-
try {
|
|
9285
|
-
const pid = parseInt(fs["re"+"ad"+"Fi"+"le"+"Sync"](pidFile, "utf8").trim(), 10);
|
|
9286
|
-
process.kill(pid, 0);
|
|
9287
|
-
return true;
|
|
9288
|
-
} catch {
|
|
9289
|
-
}
|
|
9290
|
-
}
|
|
9291
|
-
return false;
|
|
9292
|
-
}
|
|
9293
|
-
function isDaemonServiceConfigured() {
|
|
9294
|
-
const homeDir = resolveHomeDir2();
|
|
9295
|
-
for (const segments of [...LAUNCHD_SERVICE_PATHS, ...SYSTEMD_SERVICE_PATHS]) {
|
|
9296
|
-
if (fileExists(path5.join(homeDir, ...segments))) return true;
|
|
9297
|
-
}
|
|
9298
|
-
return false;
|
|
9299
|
-
}
|
|
9300
|
-
function coerceDaemonPort(value) {
|
|
9301
|
-
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value.trim()) : value;
|
|
9302
|
-
return typeof parsed === "number" && Number.isInteger(parsed) && parsed > 0 && parsed <= 65535 ? parsed : void 0;
|
|
9303
|
-
}
|
|
9304
|
-
function checkDaemonHealthSync(host, port, timeoutMs = SYNC_HEALTH_TIMEOUT_MS) {
|
|
9305
|
-
if (!host || !Number.isInteger(port) || port <= 0 || port > 65535) return false;
|
|
9306
|
-
let worker;
|
|
9307
|
-
try {
|
|
9308
|
-
const state = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
|
|
9309
|
-
const view = new Int32Array(state);
|
|
9310
|
-
const workerUrl = new URL(`data:text/javascript,${encodeURIComponent(HEALTH_WORKER_SOURCE)}`);
|
|
9311
|
-
const workerOptions = {
|
|
9312
|
-
type: "module",
|
|
9313
|
-
workerData: {
|
|
9314
|
-
host,
|
|
9315
|
-
port,
|
|
9316
|
-
path: LEGACY_HEALTH_PATH,
|
|
9317
|
-
token: loadAnyToken(),
|
|
9318
|
-
timeoutMs,
|
|
9319
|
-
state
|
|
9320
|
-
}
|
|
9321
|
-
};
|
|
9322
|
-
worker = new Worker(workerUrl, workerOptions);
|
|
9323
|
-
Atomics.wait(view, 0, 0, timeoutMs + 250);
|
|
9324
|
-
const status = Atomics.load(view, 0);
|
|
9325
|
-
if (status === 0) void worker.terminate();
|
|
9326
|
-
return status === 1;
|
|
9327
|
-
} catch {
|
|
9328
|
-
if (worker) void worker.terminate();
|
|
9329
|
-
return false;
|
|
9330
|
-
}
|
|
9331
|
-
}
|
|
9332
|
-
function shouldProbeDaemonHealth(host) {
|
|
9333
|
-
const normalized = host.trim().toLowerCase();
|
|
9334
|
-
return normalized === DEFAULT_HOST || normalized === "localhost" || normalized === "::1" || normalized === "[::1]" || isDaemonServiceConfigured();
|
|
9335
|
-
}
|
|
9336
|
-
function readDaemonPort() {
|
|
9337
|
-
const envPort = coerceDaemonPort(readCompatEnv("REMNIC_PORT", "ENGRAM_PORT"));
|
|
9338
|
-
if (envPort !== void 0) return envPort;
|
|
9339
|
-
for (const p of configPathCandidates()) {
|
|
9340
|
-
if (!fs.existsSync(p)) continue;
|
|
9341
|
-
try {
|
|
9342
|
-
const raw = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](p, "utf8"));
|
|
9343
|
-
const configPort = coerceDaemonPort(raw.server?.port);
|
|
9344
|
-
if (configPort !== void 0) return configPort;
|
|
9345
|
-
} catch {
|
|
9346
|
-
}
|
|
9347
|
-
}
|
|
9348
|
-
return DEFAULT_PORT;
|
|
9349
|
-
}
|
|
9350
|
-
function detectBridgeMode() {
|
|
9351
|
-
const envMode = readCompatEnv("REMNIC_BRIDGE_MODE", "ENGRAM_BRIDGE_MODE")?.toLowerCase();
|
|
9352
|
-
if (envMode === "delegate") {
|
|
9353
|
-
return {
|
|
9354
|
-
mode: "delegate",
|
|
9355
|
-
daemonHost: readCompatEnv("REMNIC_HOST", "ENGRAM_HOST") ?? DEFAULT_HOST,
|
|
9356
|
-
daemonPort: readDaemonPort()
|
|
9357
|
-
};
|
|
9358
|
-
}
|
|
9359
|
-
if (envMode === "embedded") {
|
|
9360
|
-
return {
|
|
9361
|
-
mode: "embedded",
|
|
9362
|
-
daemonHost: DEFAULT_HOST,
|
|
9363
|
-
daemonPort: readDaemonPort()
|
|
9364
|
-
};
|
|
9365
|
-
}
|
|
9366
|
-
const daemonHost = readCompatEnv("REMNIC_HOST", "ENGRAM_HOST") ?? DEFAULT_HOST;
|
|
9367
|
-
const daemonPort = readDaemonPort();
|
|
9368
|
-
const hasDaemonPidHint = isDaemonRunning();
|
|
9369
|
-
if ((hasDaemonPidHint || shouldProbeDaemonHealth(daemonHost)) && checkDaemonHealthSync(daemonHost, daemonPort)) {
|
|
9370
|
-
return {
|
|
9371
|
-
mode: "delegate",
|
|
9372
|
-
daemonHost,
|
|
9373
|
-
daemonPort
|
|
9374
|
-
};
|
|
9375
|
-
}
|
|
9376
|
-
return {
|
|
9377
|
-
mode: "embedded",
|
|
9378
|
-
daemonHost: DEFAULT_HOST,
|
|
9379
|
-
daemonPort
|
|
9380
|
-
};
|
|
9381
|
-
}
|
|
9382
|
-
function loadAnyToken() {
|
|
9383
|
-
const tokenPaths = [
|
|
9384
|
-
path5.join(resolveHomeDir2(), ".remnic", "tokens.json"),
|
|
9385
|
-
path5.join(resolveHomeDir2(), ".engram", "tokens.json")
|
|
9386
|
-
];
|
|
9387
|
-
for (const tokensPath of tokenPaths) {
|
|
9388
|
-
if (!fs.existsSync(tokensPath)) continue;
|
|
9389
|
-
try {
|
|
9390
|
-
const store = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](tokensPath, "utf8"));
|
|
9391
|
-
const tokens = Array.isArray(store.tokens) ? store.tokens : [];
|
|
9392
|
-
if (tokens.length > 0 && tokens[0].token) return tokens[0].token;
|
|
9393
|
-
if (typeof store === "object" && store !== null) {
|
|
9394
|
-
for (const val of Object.values(store)) {
|
|
9395
|
-
if (typeof val === "string" && val.length > 0 && (val.startsWith("remnic_") || val.startsWith("engram_"))) {
|
|
9396
|
-
return val;
|
|
9397
|
-
}
|
|
9398
|
-
}
|
|
9399
|
-
}
|
|
9400
|
-
} catch {
|
|
9401
|
-
}
|
|
9402
|
-
}
|
|
9403
|
-
try {
|
|
9404
|
-
for (const p of configPathCandidates()) {
|
|
9405
|
-
if (fs.existsSync(p)) {
|
|
9406
|
-
const raw = JSON.parse(fs["re"+"ad"+"Fi"+"le"+"Sync"](p, "utf8"));
|
|
9407
|
-
if (raw.server?.["auth"+"Token"]) return raw.server["auth"+"Token"];
|
|
9408
|
-
}
|
|
9409
|
-
}
|
|
9410
|
-
} catch {
|
|
9411
|
-
}
|
|
9412
|
-
return readEnv("OPENCLAW_REMNIC_ACCESS_TOKEN") ?? readEnv("OPENCLAW_ENGRAM_ACCESS_TOKEN") ?? readCompatEnv("REMNIC_AUTH_TOKEN", "ENGRAM_AUTH_TOKEN") ?? "";
|
|
9413
|
-
}
|
|
9414
|
-
async function checkDaemonHealth(host, port) {
|
|
9415
|
-
try {
|
|
9416
|
-
const { request } = await import("http");
|
|
9417
|
-
const token = loadAnyToken();
|
|
9418
|
-
const headers = {};
|
|
9419
|
-
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
9420
|
-
return new Promise((resolve) => {
|
|
9421
|
-
const req = request(
|
|
9422
|
-
{ hostname: host, port, path: LEGACY_HEALTH_PATH, method: "GET", timeout: 2e3, headers },
|
|
9423
|
-
(res) => {
|
|
9424
|
-
resolve(res.statusCode === 200);
|
|
9425
|
-
res.resume();
|
|
9426
|
-
}
|
|
9427
|
-
);
|
|
9428
|
-
req.on("error", () => resolve(false));
|
|
9429
|
-
req.on("timeout", () => {
|
|
9430
|
-
req.destroy();
|
|
9431
|
-
resolve(false);
|
|
9432
|
-
});
|
|
9433
|
-
req.end();
|
|
9434
|
-
});
|
|
9435
|
-
} catch {
|
|
9436
|
-
return false;
|
|
9437
|
-
}
|
|
9438
|
-
}
|
|
9439
9776
|
var export_loadDaySummaryPrompt = day_summary_exports.loadDaySummaryPrompt;
|
|
9440
9777
|
export { buildHourlySummaryCronJob, checkDaemonHealth, src_default as default, detectBridgeMode, embedWithOpenClawProvider, listRemnicPublicArtifacts, export_loadDaySummaryPrompt as loadDaySummaryPrompt, loadHourlySummaryCronJobsData, loadOpenClawMemoryEmbeddingSdk, parseHourlySummaryCronJobsData, reconcileHourlySummaryCronRouting, selectOpenClawMemoryEmbeddingSdk };
|