@securecoms/agent-bridge 0.8.0 → 0.9.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/bin.js +185 -43
- package/dist/bridge-agent.d.ts +4 -0
- package/dist/config.d.ts +4 -0
- package/dist/http-server.d.ts +4 -4
- package/dist/index.js +160 -18
- package/dist/memory/openclaw-provider.d.ts +10 -1
- package/dist/memory/openclaw-workspace-facts.d.ts +38 -0
- package/dist/memory/provider.d.ts +2 -1
- package/package.json +1 -1
- package/connectors/hermes/__pycache__/__init__.cpython-311.pyc +0 -0
- package/connectors/hermes/__pycache__/adapter.cpython-311.pyc +0 -0
- package/connectors/hermes/__pycache__/gate.cpython-311.pyc +0 -0
- package/connectors/hermes/__pycache__/securecoms_gate.cpython-311.pyc +0 -0
- package/connectors/hermes/__pycache__/securecoms_transport.cpython-311.pyc +0 -0
- package/connectors/hermes/__pycache__/transport.cpython-311.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/conftest.cpython-311-pytest-8.4.0.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/test_adapter_wiring.cpython-311-pytest-8.4.0.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/test_gate.cpython-311-pytest-8.4.0.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/test_securecoms_gate.cpython-311-pytest-8.4.0.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/test_securecoms_transport.cpython-311-pytest-8.4.0.pyc +0 -0
- package/connectors/hermes/tests/__pycache__/test_transport.cpython-311-pytest-8.4.0.pyc +0 -0
package/dist/bin.js
CHANGED
|
@@ -27,6 +27,8 @@ function loadConfig(opts) {
|
|
|
27
27
|
let memoryProvider;
|
|
28
28
|
let memoryBaseDir;
|
|
29
29
|
let memoryAgent;
|
|
30
|
+
let memoryWorkspaceDir;
|
|
31
|
+
let memoryFactsCharBudget;
|
|
30
32
|
if (memProvRaw === "none") {
|
|
31
33
|
memoryProvider = "none";
|
|
32
34
|
} else if (memProvRaw === "hermes") {
|
|
@@ -40,6 +42,10 @@ function loadConfig(opts) {
|
|
|
40
42
|
memoryBaseDir = typeof bd === "string" && bd ? bd : "~/.openclaw";
|
|
41
43
|
const ag = oc?.agent;
|
|
42
44
|
memoryAgent = typeof ag === "string" && ag ? ag : void 0;
|
|
45
|
+
const wd = oc?.workspace_dir;
|
|
46
|
+
memoryWorkspaceDir = typeof wd === "string" && wd ? wd : void 0;
|
|
47
|
+
const fb = oc?.facts_char_budget;
|
|
48
|
+
memoryFactsCharBudget = typeof fb === "number" && Number.isInteger(fb) && fb >= 0 ? fb : void 0;
|
|
43
49
|
} else {
|
|
44
50
|
memoryProvider = "securecoms";
|
|
45
51
|
}
|
|
@@ -56,7 +62,9 @@ function loadConfig(opts) {
|
|
|
56
62
|
rateLimitRefillPerMinute,
|
|
57
63
|
memoryProvider,
|
|
58
64
|
memoryBaseDir,
|
|
59
|
-
memoryAgent
|
|
65
|
+
memoryAgent,
|
|
66
|
+
memoryWorkspaceDir,
|
|
67
|
+
memoryFactsCharBudget
|
|
60
68
|
};
|
|
61
69
|
}
|
|
62
70
|
function arg(argv, flag) {
|
|
@@ -3947,7 +3955,7 @@ function loadPackageMeta(importMetaUrl) {
|
|
|
3947
3955
|
|
|
3948
3956
|
// src/bridge-agent.ts
|
|
3949
3957
|
import { promises as fsp } from "node:fs";
|
|
3950
|
-
import { join as
|
|
3958
|
+
import { join as join8, dirname as dirname3 } from "node:path";
|
|
3951
3959
|
|
|
3952
3960
|
// src/latency.ts
|
|
3953
3961
|
var DEFAULT_CAPACITY = 1024;
|
|
@@ -4460,29 +4468,153 @@ function readRecentTurns(baseDir, agent, sessionId, k) {
|
|
|
4460
4468
|
return k > 0 ? turns.slice(-k) : [];
|
|
4461
4469
|
}
|
|
4462
4470
|
|
|
4471
|
+
// src/memory/openclaw-workspace-facts.ts
|
|
4472
|
+
import { readdirSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
4473
|
+
import { join as join7 } from "node:path";
|
|
4474
|
+
var DEFAULT_FACTS_BUDGET = 8e3;
|
|
4475
|
+
var MEMORY_MD_CAP = 6e3;
|
|
4476
|
+
var MIN_FRAGMENT = 200;
|
|
4477
|
+
var MAX_SOURCE_BYTES = 1024 * 1024;
|
|
4478
|
+
var DAILY_RE = /^\d{4}-\d{2}-\d{2}\.md$/;
|
|
4479
|
+
function resolveWorkspaceDir(baseDir, agent, override) {
|
|
4480
|
+
if (override) return expandHome(override);
|
|
4481
|
+
const base = expandHome(baseDir);
|
|
4482
|
+
const isMain2 = agent === "" || agent === "main";
|
|
4483
|
+
try {
|
|
4484
|
+
const cfg = JSON.parse(readFileSync5(join7(base, "openclaw.json"), "utf8"));
|
|
4485
|
+
const agents = cfg?.agents;
|
|
4486
|
+
if (agents && typeof agents === "object") {
|
|
4487
|
+
const list = Array.isArray(agents.list) ? agents.list : [];
|
|
4488
|
+
const wanted = isMain2 ? "main" : agent;
|
|
4489
|
+
const entry = list.find((e) => e && typeof e === "object" && e.id === wanted);
|
|
4490
|
+
const ws = entry?.workspace;
|
|
4491
|
+
if (typeof ws === "string" && ws) return expandHome(ws);
|
|
4492
|
+
const def = agents.defaults?.workspace;
|
|
4493
|
+
if (typeof def === "string" && def) return expandHome(def);
|
|
4494
|
+
}
|
|
4495
|
+
} catch {
|
|
4496
|
+
}
|
|
4497
|
+
return isMain2 ? join7(base, "workspace") : join7(base, `workspace-${agent}`);
|
|
4498
|
+
}
|
|
4499
|
+
var TRUNC = "\u2026[truncated]";
|
|
4500
|
+
function headSlice(s, n) {
|
|
4501
|
+
if (s.length <= n) return { text: s, clipped: false };
|
|
4502
|
+
let out = s.slice(0, n);
|
|
4503
|
+
const last = out.charCodeAt(out.length - 1);
|
|
4504
|
+
if (last >= 55296 && last <= 56319) out = out.slice(0, -1);
|
|
4505
|
+
return { text: out, clipped: true };
|
|
4506
|
+
}
|
|
4507
|
+
function tailSlice(s, n) {
|
|
4508
|
+
if (s.length <= n) return { text: s, clipped: false };
|
|
4509
|
+
let out = s.slice(s.length - n);
|
|
4510
|
+
const first = out.charCodeAt(0);
|
|
4511
|
+
if (first >= 56320 && first <= 57343) out = out.slice(1);
|
|
4512
|
+
return { text: out, clipped: true };
|
|
4513
|
+
}
|
|
4514
|
+
function readBounded(path) {
|
|
4515
|
+
if (statSync2(path).size > MAX_SOURCE_BYTES) return { text: null, oversize: true };
|
|
4516
|
+
return { text: readFileSync5(path, "utf8"), oversize: false };
|
|
4517
|
+
}
|
|
4518
|
+
function readWorkspaceFacts(baseDir, agent, opts) {
|
|
4519
|
+
const raw = opts?.charBudget;
|
|
4520
|
+
const budget = typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : DEFAULT_FACTS_BUDGET;
|
|
4521
|
+
if (budget === 0) return { facts: [], truncated: false, missing: false };
|
|
4522
|
+
const dir = resolveWorkspaceDir(baseDir, agent, opts?.workspaceDir);
|
|
4523
|
+
const facts = [];
|
|
4524
|
+
let truncated = false;
|
|
4525
|
+
let remaining = budget;
|
|
4526
|
+
try {
|
|
4527
|
+
const r = readBounded(join7(dir, "MEMORY.md"));
|
|
4528
|
+
if (r.oversize) truncated = true;
|
|
4529
|
+
else if (r.text && r.text.trim()) {
|
|
4530
|
+
const { text, clipped } = headSlice(r.text, Math.min(MEMORY_MD_CAP, budget));
|
|
4531
|
+
truncated ||= clipped;
|
|
4532
|
+
facts.push(`workspace MEMORY.md:
|
|
4533
|
+
${text}${clipped ? `
|
|
4534
|
+
${TRUNC}` : ""}`);
|
|
4535
|
+
remaining -= text.length;
|
|
4536
|
+
}
|
|
4537
|
+
} catch {
|
|
4538
|
+
}
|
|
4539
|
+
try {
|
|
4540
|
+
const dailies = readdirSync(join7(dir, "memory")).filter((f) => DAILY_RE.test(f)).sort().reverse().slice(0, 2);
|
|
4541
|
+
for (const f of dailies) {
|
|
4542
|
+
if (remaining < MIN_FRAGMENT) {
|
|
4543
|
+
truncated = true;
|
|
4544
|
+
break;
|
|
4545
|
+
}
|
|
4546
|
+
let r;
|
|
4547
|
+
try {
|
|
4548
|
+
r = readBounded(join7(dir, "memory", f));
|
|
4549
|
+
} catch {
|
|
4550
|
+
continue;
|
|
4551
|
+
}
|
|
4552
|
+
if (r.oversize) {
|
|
4553
|
+
truncated = true;
|
|
4554
|
+
continue;
|
|
4555
|
+
}
|
|
4556
|
+
if (!r.text || !r.text.trim()) continue;
|
|
4557
|
+
const { text, clipped } = tailSlice(r.text, remaining);
|
|
4558
|
+
truncated ||= clipped;
|
|
4559
|
+
facts.push(`workspace memory/${f} (daily):
|
|
4560
|
+
${clipped ? `${TRUNC}
|
|
4561
|
+
` : ""}${text}`);
|
|
4562
|
+
remaining -= text.length;
|
|
4563
|
+
}
|
|
4564
|
+
} catch {
|
|
4565
|
+
}
|
|
4566
|
+
return { facts, truncated, missing: facts.length === 0 };
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4463
4569
|
// src/memory/openclaw-provider.ts
|
|
4464
4570
|
var DEFAULT_K2 = 200;
|
|
4465
4571
|
var OpenClawMemoryProvider = class {
|
|
4466
|
-
|
|
4572
|
+
// gauge: last successful returned total, including prefixes/markers
|
|
4573
|
+
constructor(store, baseDir, agent, factsOpts) {
|
|
4467
4574
|
this.store = store;
|
|
4468
4575
|
this.baseDir = baseDir;
|
|
4469
4576
|
this.agent = agent;
|
|
4577
|
+
this.factsOpts = factsOpts;
|
|
4470
4578
|
}
|
|
4471
4579
|
noSession = 0;
|
|
4472
4580
|
readFailed = 0;
|
|
4581
|
+
factsMissing = 0;
|
|
4582
|
+
// absence-shaped: resolved path missing or zero sources (per-call)
|
|
4583
|
+
factsReadFailed = 0;
|
|
4584
|
+
// anything THROWN out of the facts computation
|
|
4585
|
+
factsTruncated = 0;
|
|
4586
|
+
// budget clipped/dropped a source (incl. the 1MB skip)
|
|
4587
|
+
factsChars = 0;
|
|
4473
4588
|
async record(input) {
|
|
4474
4589
|
if (input.modality !== "voice") return { seq: 0, deduped: true };
|
|
4475
4590
|
return this.store.recordMemory({ ...input, text: `[voice] ${input.text}` });
|
|
4476
4591
|
}
|
|
4477
4592
|
async context(conversationId, limit) {
|
|
4478
4593
|
const k = limit ?? DEFAULT_K2;
|
|
4594
|
+
let wsFacts = [];
|
|
4595
|
+
try {
|
|
4596
|
+
const r = readWorkspaceFacts(this.baseDir, this.agent, {
|
|
4597
|
+
workspaceDir: this.factsOpts?.workspaceDir,
|
|
4598
|
+
charBudget: this.factsOpts?.factsCharBudget
|
|
4599
|
+
});
|
|
4600
|
+
wsFacts = r.facts;
|
|
4601
|
+
if (r.missing) this.factsMissing++;
|
|
4602
|
+
if (r.truncated) this.factsTruncated++;
|
|
4603
|
+
this.factsChars = r.facts.reduce((n, f) => n + f.length, 0);
|
|
4604
|
+
} catch {
|
|
4605
|
+
this.factsReadFailed++;
|
|
4606
|
+
}
|
|
4607
|
+
const withFacts = (res) => ({
|
|
4608
|
+
recent: res.recent,
|
|
4609
|
+
facts: [...wsFacts, ...res.facts]
|
|
4610
|
+
});
|
|
4479
4611
|
const voice = await this.store.memoryContext(conversationId, k);
|
|
4480
4612
|
let textTurns = [];
|
|
4481
4613
|
try {
|
|
4482
4614
|
const sid = resolveOwnerDmSession(this.baseDir, this.agent);
|
|
4483
4615
|
if (!sid) {
|
|
4484
4616
|
this.noSession++;
|
|
4485
|
-
return voice;
|
|
4617
|
+
return withFacts(voice);
|
|
4486
4618
|
}
|
|
4487
4619
|
textTurns = readRecentTurns(this.baseDir, this.agent, sid, k).map((t) => ({
|
|
4488
4620
|
seq: 0,
|
|
@@ -4492,7 +4624,7 @@ var OpenClawMemoryProvider = class {
|
|
|
4492
4624
|
}));
|
|
4493
4625
|
} catch {
|
|
4494
4626
|
this.readFailed++;
|
|
4495
|
-
return voice;
|
|
4627
|
+
return withFacts(voice);
|
|
4496
4628
|
}
|
|
4497
4629
|
const tagged = [
|
|
4498
4630
|
...textTurns.map((t, i) => ({ ...t, _src: 0, _i: i })),
|
|
@@ -4511,10 +4643,17 @@ var OpenClawMemoryProvider = class {
|
|
|
4511
4643
|
text: t.text,
|
|
4512
4644
|
ts: t.ts
|
|
4513
4645
|
}));
|
|
4514
|
-
return { recent, facts: voice.facts };
|
|
4646
|
+
return withFacts({ recent, facts: voice.facts });
|
|
4515
4647
|
}
|
|
4516
4648
|
stats() {
|
|
4517
|
-
return {
|
|
4649
|
+
return {
|
|
4650
|
+
openclaw_no_session: this.noSession,
|
|
4651
|
+
openclaw_read_failed: this.readFailed,
|
|
4652
|
+
openclaw_facts_missing: this.factsMissing,
|
|
4653
|
+
openclaw_facts_read_failed: this.factsReadFailed,
|
|
4654
|
+
openclaw_facts_truncated: this.factsTruncated,
|
|
4655
|
+
openclaw_facts_chars: this.factsChars
|
|
4656
|
+
};
|
|
4518
4657
|
}
|
|
4519
4658
|
};
|
|
4520
4659
|
|
|
@@ -4538,10 +4677,10 @@ var NullMemory = class {
|
|
|
4538
4677
|
return { recent: [], facts: [] };
|
|
4539
4678
|
}
|
|
4540
4679
|
};
|
|
4541
|
-
function createMemoryProvider(provider, store, baseDir, agent) {
|
|
4680
|
+
function createMemoryProvider(provider, store, baseDir, agent, openclawFacts) {
|
|
4542
4681
|
if (provider === "none") return new NullMemory();
|
|
4543
4682
|
if (provider === "hermes") return new HermesMemoryProvider(baseDir ?? "~/.hermes");
|
|
4544
|
-
if (provider === "openclaw") return new OpenClawMemoryProvider(store, baseDir ?? "~/.openclaw", agent ?? "");
|
|
4683
|
+
if (provider === "openclaw") return new OpenClawMemoryProvider(store, baseDir ?? "~/.openclaw", agent ?? "", openclawFacts);
|
|
4545
4684
|
return new SecureComsLocalMemory(store);
|
|
4546
4685
|
}
|
|
4547
4686
|
|
|
@@ -4649,7 +4788,10 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
4649
4788
|
identityId: cfg.identityId,
|
|
4650
4789
|
cipherFor: () => new KeyedInboxCipher(deriveMlsStoreKey(seed))
|
|
4651
4790
|
});
|
|
4652
|
-
this.memory = createMemoryProvider(this.cfg.memoryProvider, this.store, this.cfg.memoryBaseDir, this.cfg.memoryAgent
|
|
4791
|
+
this.memory = createMemoryProvider(this.cfg.memoryProvider, this.store, this.cfg.memoryBaseDir, this.cfg.memoryAgent, {
|
|
4792
|
+
workspaceDir: this.cfg.memoryWorkspaceDir,
|
|
4793
|
+
factsCharBudget: this.cfg.memoryFactsCharBudget
|
|
4794
|
+
});
|
|
4653
4795
|
this.provider = new MlsGroupKeyProvider({
|
|
4654
4796
|
store: this.store,
|
|
4655
4797
|
backend: this.backend,
|
|
@@ -4729,7 +4871,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
4729
4871
|
const j = await res.json();
|
|
4730
4872
|
return String(j.attachment_id);
|
|
4731
4873
|
};
|
|
4732
|
-
this.attachmentsDirImpl = deps.attachmentsDir ??
|
|
4874
|
+
this.attachmentsDirImpl = deps.attachmentsDir ?? join8(dirname3(cfg.storePath), "attachments");
|
|
4733
4875
|
this.action = {
|
|
4734
4876
|
begin: (channelId) => this.actionBegin(channelId),
|
|
4735
4877
|
start: (opts) => this.actionStart(opts),
|
|
@@ -6257,11 +6399,11 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
6257
6399
|
|
|
6258
6400
|
// src/auth.ts
|
|
6259
6401
|
import { randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
6260
|
-
import { existsSync, readFileSync as
|
|
6402
|
+
import { existsSync, readFileSync as readFileSync6, writeFileSync } from "node:fs";
|
|
6261
6403
|
function resolveToken(opts) {
|
|
6262
6404
|
if (opts.token) return opts.token;
|
|
6263
6405
|
const f = opts.tokenFile;
|
|
6264
|
-
if (f && existsSync(f)) return
|
|
6406
|
+
if (f && existsSync(f)) return readFileSync6(f, "utf8").trim();
|
|
6265
6407
|
const tok = randomBytes3(32).toString("base64url");
|
|
6266
6408
|
if (f) writeFileSync(f, tok, { mode: 384 });
|
|
6267
6409
|
return tok;
|
|
@@ -6832,8 +6974,8 @@ async function handleInbound(sock, agent, data, inflight) {
|
|
|
6832
6974
|
}
|
|
6833
6975
|
|
|
6834
6976
|
// src/bin.ts
|
|
6835
|
-
import { readFileSync as
|
|
6836
|
-
import { join as
|
|
6977
|
+
import { readFileSync as readFileSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, rmSync, existsSync as existsSync2, realpathSync, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
|
|
6978
|
+
import { join as join12, dirname as dirname7, isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
6837
6979
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6838
6980
|
import { homedir as homedir2, userInfo } from "node:os";
|
|
6839
6981
|
import { spawnSync } from "node:child_process";
|
|
@@ -7042,10 +7184,10 @@ function uninstallService(input, deps) {
|
|
|
7042
7184
|
}
|
|
7043
7185
|
|
|
7044
7186
|
// src/service/install-prep.ts
|
|
7045
|
-
import { join as
|
|
7187
|
+
import { join as join10 } from "node:path";
|
|
7046
7188
|
|
|
7047
7189
|
// src/service/wire.ts
|
|
7048
|
-
import { join as
|
|
7190
|
+
import { join as join9, dirname as dirname5 } from "node:path";
|
|
7049
7191
|
import { fileURLToPath } from "node:url";
|
|
7050
7192
|
|
|
7051
7193
|
// src/service/hermes-config.ts
|
|
@@ -7211,7 +7353,7 @@ function connectorTargetDir(home, harness) {
|
|
|
7211
7353
|
}
|
|
7212
7354
|
function connectorsSrcDir(importMetaUrl, harness) {
|
|
7213
7355
|
const pkgRoot = dirname5(dirname5(fileURLToPath(importMetaUrl)));
|
|
7214
|
-
return
|
|
7356
|
+
return join9(pkgRoot, "connectors", harness);
|
|
7215
7357
|
}
|
|
7216
7358
|
function hermesConfigPath(home) {
|
|
7217
7359
|
return `${home}/.hermes/config.yaml`;
|
|
@@ -7430,10 +7572,10 @@ function assertReadableCredential(absPath, deps) {
|
|
|
7430
7572
|
return { deviceId: json2.device_id, identityId: json2.identity_id, issuedAt };
|
|
7431
7573
|
}
|
|
7432
7574
|
function durableDir(home, slug) {
|
|
7433
|
-
return
|
|
7575
|
+
return join10(home, `securecoms-agent-${slug}`);
|
|
7434
7576
|
}
|
|
7435
7577
|
function durableCredentialPath(home, slug) {
|
|
7436
|
-
return
|
|
7578
|
+
return join10(durableDir(home, slug), `${slug}.json`);
|
|
7437
7579
|
}
|
|
7438
7580
|
function takeCustody(args2, deps) {
|
|
7439
7581
|
const dir = durableDir(args2.home, args2.slug);
|
|
@@ -7480,7 +7622,7 @@ function readSiblingDefs(dir, prefix, deps) {
|
|
|
7480
7622
|
for (const n of names) {
|
|
7481
7623
|
if (!n.startsWith(prefix)) continue;
|
|
7482
7624
|
try {
|
|
7483
|
-
out.push(deps.readFile(
|
|
7625
|
+
out.push(deps.readFile(join10(dir, n)));
|
|
7484
7626
|
} catch {
|
|
7485
7627
|
}
|
|
7486
7628
|
}
|
|
@@ -7676,29 +7818,29 @@ function renderStatusTable(rows) {
|
|
|
7676
7818
|
import {
|
|
7677
7819
|
chmodSync,
|
|
7678
7820
|
mkdirSync,
|
|
7679
|
-
readFileSync as
|
|
7821
|
+
readFileSync as readFileSync7,
|
|
7680
7822
|
renameSync,
|
|
7681
7823
|
unlinkSync,
|
|
7682
7824
|
writeFileSync as writeFileSync2
|
|
7683
7825
|
} from "node:fs";
|
|
7684
7826
|
import { randomUUID } from "node:crypto";
|
|
7685
|
-
import { join as
|
|
7827
|
+
import { join as join11 } from "node:path";
|
|
7686
7828
|
var REAL_FS = {
|
|
7687
7829
|
mkdir: (p, mode) => mkdirSync(p, { recursive: true, mode }),
|
|
7688
7830
|
chmod: (p, mode) => chmodSync(p, mode),
|
|
7689
7831
|
writeFile: (p, data, mode) => writeFileSync2(p, data, { mode }),
|
|
7690
7832
|
rename: (a, b) => renameSync(a, b),
|
|
7691
|
-
readFile: (p) =>
|
|
7833
|
+
readFile: (p) => readFileSync7(p, "utf8"),
|
|
7692
7834
|
unlink: (p) => unlinkSync(p)
|
|
7693
7835
|
};
|
|
7694
7836
|
function securecomsDir(home) {
|
|
7695
|
-
return
|
|
7837
|
+
return join11(home, ".securecoms");
|
|
7696
7838
|
}
|
|
7697
7839
|
function connectionsDir(home) {
|
|
7698
|
-
return
|
|
7840
|
+
return join11(securecomsDir(home), "connections");
|
|
7699
7841
|
}
|
|
7700
7842
|
function connectionFilePath(home, identityId) {
|
|
7701
|
-
return
|
|
7843
|
+
return join11(connectionsDir(home), `${identityId}.json`);
|
|
7702
7844
|
}
|
|
7703
7845
|
function newInstanceId() {
|
|
7704
7846
|
return randomUUID();
|
|
@@ -7813,7 +7955,7 @@ function realResolveDeps() {
|
|
|
7813
7955
|
}
|
|
7814
7956
|
function realPrepDeps() {
|
|
7815
7957
|
return {
|
|
7816
|
-
readFile: (p) =>
|
|
7958
|
+
readFile: (p) => readFileSync8(p, "utf8"),
|
|
7817
7959
|
writeFileMode: (p, data, mode) => writeFileSync3(p, data, { mode }),
|
|
7818
7960
|
mkdirp: (p, mode) => {
|
|
7819
7961
|
mkdirSync2(p, { recursive: true, mode: mode ?? 493 });
|
|
@@ -7822,7 +7964,7 @@ function realPrepDeps() {
|
|
|
7822
7964
|
realpath: (p) => realpathSync(p),
|
|
7823
7965
|
listDir: (p) => {
|
|
7824
7966
|
try {
|
|
7825
|
-
return
|
|
7967
|
+
return readdirSync2(p);
|
|
7826
7968
|
} catch {
|
|
7827
7969
|
return [];
|
|
7828
7970
|
}
|
|
@@ -7864,12 +8006,12 @@ function realReadFleet() {
|
|
|
7864
8006
|
home: homedir2(),
|
|
7865
8007
|
listDir: (p) => {
|
|
7866
8008
|
try {
|
|
7867
|
-
return
|
|
8009
|
+
return readdirSync2(p);
|
|
7868
8010
|
} catch {
|
|
7869
8011
|
return [];
|
|
7870
8012
|
}
|
|
7871
8013
|
},
|
|
7872
|
-
readFile: (p) =>
|
|
8014
|
+
readFile: (p) => readFileSync8(p, "utf8")
|
|
7873
8015
|
});
|
|
7874
8016
|
}
|
|
7875
8017
|
function runStatus() {
|
|
@@ -7892,43 +8034,43 @@ function runStatus() {
|
|
|
7892
8034
|
function realCopyConnector(srcDir, dstDir, harness) {
|
|
7893
8035
|
const allowedExt = CONNECTOR_FILE_EXTENSIONS[harness];
|
|
7894
8036
|
mkdirSync2(dstDir, { recursive: true });
|
|
7895
|
-
for (const name of
|
|
7896
|
-
const srcPath =
|
|
7897
|
-
if (
|
|
8037
|
+
for (const name of readdirSync2(srcDir)) {
|
|
8038
|
+
const srcPath = join12(srcDir, name);
|
|
8039
|
+
if (statSync3(srcPath).isDirectory()) {
|
|
7898
8040
|
if (CONNECTOR_SKIP_DIRS.has(name)) continue;
|
|
7899
|
-
realCopyConnector(srcPath,
|
|
8041
|
+
realCopyConnector(srcPath, join12(dstDir, name), harness);
|
|
7900
8042
|
continue;
|
|
7901
8043
|
}
|
|
7902
8044
|
if (name.includes(".test.")) continue;
|
|
7903
8045
|
if (!allowedExt.some((ext) => name.endsWith(ext))) continue;
|
|
7904
|
-
writeFileSync3(
|
|
8046
|
+
writeFileSync3(join12(dstDir, name), readFileSync8(srcPath));
|
|
7905
8047
|
}
|
|
7906
8048
|
}
|
|
7907
8049
|
function realWriteBinding(dstDir, identityId) {
|
|
7908
8050
|
mkdirSync2(dstDir, { recursive: true });
|
|
7909
|
-
writeFileSync3(
|
|
8051
|
+
writeFileSync3(join12(dstDir, "securecoms.binding.json"), JSON.stringify({ identity_id: identityId }) + "\n", { mode: 384 });
|
|
7910
8052
|
}
|
|
7911
8053
|
function realReadBinding(dstDir) {
|
|
7912
8054
|
try {
|
|
7913
|
-
const parsed = JSON.parse(
|
|
8055
|
+
const parsed = JSON.parse(readFileSync8(join12(dstDir, "securecoms.binding.json"), "utf8"));
|
|
7914
8056
|
return parsed.identity_id ?? null;
|
|
7915
8057
|
} catch {
|
|
7916
8058
|
return null;
|
|
7917
8059
|
}
|
|
7918
8060
|
}
|
|
7919
8061
|
function realRemoveBinding(dstDir) {
|
|
7920
|
-
rmSync(
|
|
8062
|
+
rmSync(join12(dstDir, "securecoms.binding.json"), { force: true });
|
|
7921
8063
|
}
|
|
7922
8064
|
function realStatDir(p) {
|
|
7923
8065
|
try {
|
|
7924
|
-
return
|
|
8066
|
+
return statSync3(p).isDirectory();
|
|
7925
8067
|
} catch {
|
|
7926
8068
|
return false;
|
|
7927
8069
|
}
|
|
7928
8070
|
}
|
|
7929
8071
|
function realReadHermesConfig(p) {
|
|
7930
8072
|
try {
|
|
7931
|
-
return
|
|
8073
|
+
return readFileSync8(p, "utf8");
|
|
7932
8074
|
} catch {
|
|
7933
8075
|
return null;
|
|
7934
8076
|
}
|
|
@@ -8087,11 +8229,11 @@ async function main() {
|
|
|
8087
8229
|
`);
|
|
8088
8230
|
process.exit(1);
|
|
8089
8231
|
}
|
|
8090
|
-
const tokenFile = daemon.tokenFile ??
|
|
8232
|
+
const tokenFile = daemon.tokenFile ?? join12(dirname7(credentialPath), "bridge-token");
|
|
8091
8233
|
const token = resolveToken({ tokenFile, token: daemon.token });
|
|
8092
8234
|
const agent = new BridgeAgent(cfg);
|
|
8093
8235
|
await agent.start();
|
|
8094
|
-
const tls = daemon.tls ? { cert:
|
|
8236
|
+
const tls = daemon.tls ? { cert: readFileSync8(daemon.tlsCert, "utf8"), key: readFileSync8(daemon.tlsKey, "utf8") } : void 0;
|
|
8095
8237
|
const { server, closeAllSseStreams } = createHttpServer(agent, { token, allowOrigins: daemon.allowOrigins, tls, websocket: true });
|
|
8096
8238
|
const agentWs = attachAgentWebSocket(server, agent, { token, allowOrigins: daemon.allowOrigins });
|
|
8097
8239
|
let down = false;
|
package/dist/bridge-agent.d.ts
CHANGED
|
@@ -842,6 +842,10 @@ export declare class BridgeAgent {
|
|
|
842
842
|
hermes_write_failed?: number;
|
|
843
843
|
openclaw_no_session?: number;
|
|
844
844
|
openclaw_read_failed?: number;
|
|
845
|
+
openclaw_facts_missing?: number;
|
|
846
|
+
openclaw_facts_read_failed?: number;
|
|
847
|
+
openclaw_facts_truncated?: number;
|
|
848
|
+
openclaw_facts_chars?: number;
|
|
845
849
|
};
|
|
846
850
|
/**
|
|
847
851
|
* Loopback observability snapshot served at GET /v1/metrics.
|
package/dist/config.d.ts
CHANGED
|
@@ -23,6 +23,10 @@ export interface BridgeConfig {
|
|
|
23
23
|
memoryBaseDir?: string;
|
|
24
24
|
/** For memoryProvider="openclaw": the OpenClaw agent dir slug, e.g. "cortina" (→ <base_dir>/agents/<agent>/). */
|
|
25
25
|
memoryAgent?: string;
|
|
26
|
+
/** For memoryProvider="openclaw": explicit workspace dir override; wins over openclaw.json (spec D4 rung 1). */
|
|
27
|
+
memoryWorkspaceDir?: string;
|
|
28
|
+
/** For memoryProvider="openclaw": total facts cap in UTF-16 code units. 0 = facts kill switch (preserved via ?? downstream, never ||). Absent/junk → provider default 8000. */
|
|
29
|
+
memoryFactsCharBudget?: number;
|
|
26
30
|
}
|
|
27
31
|
export declare const REQUIRED: readonly ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
|
|
28
32
|
export declare function loadConfig(opts: {
|
package/dist/http-server.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare const memoryRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
34
34
|
message_id: z.ZodOptional<z.ZodString>;
|
|
35
35
|
idempotency_key: z.ZodOptional<z.ZodString>;
|
|
36
36
|
}, "strip", z.ZodTypeAny, {
|
|
37
|
-
role: "
|
|
37
|
+
role: "agent" | "peer";
|
|
38
38
|
text: string;
|
|
39
39
|
conversation_id: string;
|
|
40
40
|
modality: "text" | "voice";
|
|
@@ -42,7 +42,7 @@ export declare const memoryRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
42
42
|
idempotency_key?: string | undefined;
|
|
43
43
|
peer_id?: string | undefined;
|
|
44
44
|
}, {
|
|
45
|
-
role: "
|
|
45
|
+
role: "agent" | "peer";
|
|
46
46
|
text: string;
|
|
47
47
|
conversation_id: string;
|
|
48
48
|
modality: "text" | "voice";
|
|
@@ -50,7 +50,7 @@ export declare const memoryRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
50
50
|
idempotency_key?: string | undefined;
|
|
51
51
|
peer_id?: string | undefined;
|
|
52
52
|
}>, {
|
|
53
|
-
role: "
|
|
53
|
+
role: "agent" | "peer";
|
|
54
54
|
text: string;
|
|
55
55
|
conversation_id: string;
|
|
56
56
|
modality: "text" | "voice";
|
|
@@ -58,7 +58,7 @@ export declare const memoryRecordSchema: z.ZodEffects<z.ZodObject<{
|
|
|
58
58
|
idempotency_key?: string | undefined;
|
|
59
59
|
peer_id?: string | undefined;
|
|
60
60
|
}, {
|
|
61
|
-
role: "
|
|
61
|
+
role: "agent" | "peer";
|
|
62
62
|
text: string;
|
|
63
63
|
conversation_id: string;
|
|
64
64
|
modality: "text" | "voice";
|
package/dist/index.js
CHANGED
|
@@ -3811,7 +3811,7 @@ function loadPackageMeta(importMetaUrl) {
|
|
|
3811
3811
|
|
|
3812
3812
|
// src/bridge-agent.ts
|
|
3813
3813
|
import { promises as fsp } from "node:fs";
|
|
3814
|
-
import { join as
|
|
3814
|
+
import { join as join6, dirname } from "node:path";
|
|
3815
3815
|
|
|
3816
3816
|
// src/latency.ts
|
|
3817
3817
|
var DEFAULT_CAPACITY = 1024;
|
|
@@ -4324,29 +4324,153 @@ function readRecentTurns(baseDir, agent, sessionId, k) {
|
|
|
4324
4324
|
return k > 0 ? turns.slice(-k) : [];
|
|
4325
4325
|
}
|
|
4326
4326
|
|
|
4327
|
+
// src/memory/openclaw-workspace-facts.ts
|
|
4328
|
+
import { readdirSync, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
4329
|
+
import { join as join5 } from "node:path";
|
|
4330
|
+
var DEFAULT_FACTS_BUDGET = 8e3;
|
|
4331
|
+
var MEMORY_MD_CAP = 6e3;
|
|
4332
|
+
var MIN_FRAGMENT = 200;
|
|
4333
|
+
var MAX_SOURCE_BYTES = 1024 * 1024;
|
|
4334
|
+
var DAILY_RE = /^\d{4}-\d{2}-\d{2}\.md$/;
|
|
4335
|
+
function resolveWorkspaceDir(baseDir, agent, override) {
|
|
4336
|
+
if (override) return expandHome(override);
|
|
4337
|
+
const base = expandHome(baseDir);
|
|
4338
|
+
const isMain = agent === "" || agent === "main";
|
|
4339
|
+
try {
|
|
4340
|
+
const cfg = JSON.parse(readFileSync4(join5(base, "openclaw.json"), "utf8"));
|
|
4341
|
+
const agents = cfg?.agents;
|
|
4342
|
+
if (agents && typeof agents === "object") {
|
|
4343
|
+
const list = Array.isArray(agents.list) ? agents.list : [];
|
|
4344
|
+
const wanted = isMain ? "main" : agent;
|
|
4345
|
+
const entry = list.find((e) => e && typeof e === "object" && e.id === wanted);
|
|
4346
|
+
const ws = entry?.workspace;
|
|
4347
|
+
if (typeof ws === "string" && ws) return expandHome(ws);
|
|
4348
|
+
const def = agents.defaults?.workspace;
|
|
4349
|
+
if (typeof def === "string" && def) return expandHome(def);
|
|
4350
|
+
}
|
|
4351
|
+
} catch {
|
|
4352
|
+
}
|
|
4353
|
+
return isMain ? join5(base, "workspace") : join5(base, `workspace-${agent}`);
|
|
4354
|
+
}
|
|
4355
|
+
var TRUNC = "\u2026[truncated]";
|
|
4356
|
+
function headSlice(s, n) {
|
|
4357
|
+
if (s.length <= n) return { text: s, clipped: false };
|
|
4358
|
+
let out = s.slice(0, n);
|
|
4359
|
+
const last = out.charCodeAt(out.length - 1);
|
|
4360
|
+
if (last >= 55296 && last <= 56319) out = out.slice(0, -1);
|
|
4361
|
+
return { text: out, clipped: true };
|
|
4362
|
+
}
|
|
4363
|
+
function tailSlice(s, n) {
|
|
4364
|
+
if (s.length <= n) return { text: s, clipped: false };
|
|
4365
|
+
let out = s.slice(s.length - n);
|
|
4366
|
+
const first = out.charCodeAt(0);
|
|
4367
|
+
if (first >= 56320 && first <= 57343) out = out.slice(1);
|
|
4368
|
+
return { text: out, clipped: true };
|
|
4369
|
+
}
|
|
4370
|
+
function readBounded(path) {
|
|
4371
|
+
if (statSync(path).size > MAX_SOURCE_BYTES) return { text: null, oversize: true };
|
|
4372
|
+
return { text: readFileSync4(path, "utf8"), oversize: false };
|
|
4373
|
+
}
|
|
4374
|
+
function readWorkspaceFacts(baseDir, agent, opts) {
|
|
4375
|
+
const raw = opts?.charBudget;
|
|
4376
|
+
const budget = typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : DEFAULT_FACTS_BUDGET;
|
|
4377
|
+
if (budget === 0) return { facts: [], truncated: false, missing: false };
|
|
4378
|
+
const dir = resolveWorkspaceDir(baseDir, agent, opts?.workspaceDir);
|
|
4379
|
+
const facts = [];
|
|
4380
|
+
let truncated = false;
|
|
4381
|
+
let remaining = budget;
|
|
4382
|
+
try {
|
|
4383
|
+
const r = readBounded(join5(dir, "MEMORY.md"));
|
|
4384
|
+
if (r.oversize) truncated = true;
|
|
4385
|
+
else if (r.text && r.text.trim()) {
|
|
4386
|
+
const { text, clipped } = headSlice(r.text, Math.min(MEMORY_MD_CAP, budget));
|
|
4387
|
+
truncated ||= clipped;
|
|
4388
|
+
facts.push(`workspace MEMORY.md:
|
|
4389
|
+
${text}${clipped ? `
|
|
4390
|
+
${TRUNC}` : ""}`);
|
|
4391
|
+
remaining -= text.length;
|
|
4392
|
+
}
|
|
4393
|
+
} catch {
|
|
4394
|
+
}
|
|
4395
|
+
try {
|
|
4396
|
+
const dailies = readdirSync(join5(dir, "memory")).filter((f) => DAILY_RE.test(f)).sort().reverse().slice(0, 2);
|
|
4397
|
+
for (const f of dailies) {
|
|
4398
|
+
if (remaining < MIN_FRAGMENT) {
|
|
4399
|
+
truncated = true;
|
|
4400
|
+
break;
|
|
4401
|
+
}
|
|
4402
|
+
let r;
|
|
4403
|
+
try {
|
|
4404
|
+
r = readBounded(join5(dir, "memory", f));
|
|
4405
|
+
} catch {
|
|
4406
|
+
continue;
|
|
4407
|
+
}
|
|
4408
|
+
if (r.oversize) {
|
|
4409
|
+
truncated = true;
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
if (!r.text || !r.text.trim()) continue;
|
|
4413
|
+
const { text, clipped } = tailSlice(r.text, remaining);
|
|
4414
|
+
truncated ||= clipped;
|
|
4415
|
+
facts.push(`workspace memory/${f} (daily):
|
|
4416
|
+
${clipped ? `${TRUNC}
|
|
4417
|
+
` : ""}${text}`);
|
|
4418
|
+
remaining -= text.length;
|
|
4419
|
+
}
|
|
4420
|
+
} catch {
|
|
4421
|
+
}
|
|
4422
|
+
return { facts, truncated, missing: facts.length === 0 };
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4327
4425
|
// src/memory/openclaw-provider.ts
|
|
4328
4426
|
var DEFAULT_K2 = 200;
|
|
4329
4427
|
var OpenClawMemoryProvider = class {
|
|
4330
|
-
|
|
4428
|
+
// gauge: last successful returned total, including prefixes/markers
|
|
4429
|
+
constructor(store, baseDir, agent, factsOpts) {
|
|
4331
4430
|
this.store = store;
|
|
4332
4431
|
this.baseDir = baseDir;
|
|
4333
4432
|
this.agent = agent;
|
|
4433
|
+
this.factsOpts = factsOpts;
|
|
4334
4434
|
}
|
|
4335
4435
|
noSession = 0;
|
|
4336
4436
|
readFailed = 0;
|
|
4437
|
+
factsMissing = 0;
|
|
4438
|
+
// absence-shaped: resolved path missing or zero sources (per-call)
|
|
4439
|
+
factsReadFailed = 0;
|
|
4440
|
+
// anything THROWN out of the facts computation
|
|
4441
|
+
factsTruncated = 0;
|
|
4442
|
+
// budget clipped/dropped a source (incl. the 1MB skip)
|
|
4443
|
+
factsChars = 0;
|
|
4337
4444
|
async record(input) {
|
|
4338
4445
|
if (input.modality !== "voice") return { seq: 0, deduped: true };
|
|
4339
4446
|
return this.store.recordMemory({ ...input, text: `[voice] ${input.text}` });
|
|
4340
4447
|
}
|
|
4341
4448
|
async context(conversationId, limit) {
|
|
4342
4449
|
const k = limit ?? DEFAULT_K2;
|
|
4450
|
+
let wsFacts = [];
|
|
4451
|
+
try {
|
|
4452
|
+
const r = readWorkspaceFacts(this.baseDir, this.agent, {
|
|
4453
|
+
workspaceDir: this.factsOpts?.workspaceDir,
|
|
4454
|
+
charBudget: this.factsOpts?.factsCharBudget
|
|
4455
|
+
});
|
|
4456
|
+
wsFacts = r.facts;
|
|
4457
|
+
if (r.missing) this.factsMissing++;
|
|
4458
|
+
if (r.truncated) this.factsTruncated++;
|
|
4459
|
+
this.factsChars = r.facts.reduce((n, f) => n + f.length, 0);
|
|
4460
|
+
} catch {
|
|
4461
|
+
this.factsReadFailed++;
|
|
4462
|
+
}
|
|
4463
|
+
const withFacts = (res) => ({
|
|
4464
|
+
recent: res.recent,
|
|
4465
|
+
facts: [...wsFacts, ...res.facts]
|
|
4466
|
+
});
|
|
4343
4467
|
const voice = await this.store.memoryContext(conversationId, k);
|
|
4344
4468
|
let textTurns = [];
|
|
4345
4469
|
try {
|
|
4346
4470
|
const sid = resolveOwnerDmSession(this.baseDir, this.agent);
|
|
4347
4471
|
if (!sid) {
|
|
4348
4472
|
this.noSession++;
|
|
4349
|
-
return voice;
|
|
4473
|
+
return withFacts(voice);
|
|
4350
4474
|
}
|
|
4351
4475
|
textTurns = readRecentTurns(this.baseDir, this.agent, sid, k).map((t) => ({
|
|
4352
4476
|
seq: 0,
|
|
@@ -4356,7 +4480,7 @@ var OpenClawMemoryProvider = class {
|
|
|
4356
4480
|
}));
|
|
4357
4481
|
} catch {
|
|
4358
4482
|
this.readFailed++;
|
|
4359
|
-
return voice;
|
|
4483
|
+
return withFacts(voice);
|
|
4360
4484
|
}
|
|
4361
4485
|
const tagged = [
|
|
4362
4486
|
...textTurns.map((t, i) => ({ ...t, _src: 0, _i: i })),
|
|
@@ -4375,10 +4499,17 @@ var OpenClawMemoryProvider = class {
|
|
|
4375
4499
|
text: t.text,
|
|
4376
4500
|
ts: t.ts
|
|
4377
4501
|
}));
|
|
4378
|
-
return { recent, facts: voice.facts };
|
|
4502
|
+
return withFacts({ recent, facts: voice.facts });
|
|
4379
4503
|
}
|
|
4380
4504
|
stats() {
|
|
4381
|
-
return {
|
|
4505
|
+
return {
|
|
4506
|
+
openclaw_no_session: this.noSession,
|
|
4507
|
+
openclaw_read_failed: this.readFailed,
|
|
4508
|
+
openclaw_facts_missing: this.factsMissing,
|
|
4509
|
+
openclaw_facts_read_failed: this.factsReadFailed,
|
|
4510
|
+
openclaw_facts_truncated: this.factsTruncated,
|
|
4511
|
+
openclaw_facts_chars: this.factsChars
|
|
4512
|
+
};
|
|
4382
4513
|
}
|
|
4383
4514
|
};
|
|
4384
4515
|
|
|
@@ -4402,10 +4533,10 @@ var NullMemory = class {
|
|
|
4402
4533
|
return { recent: [], facts: [] };
|
|
4403
4534
|
}
|
|
4404
4535
|
};
|
|
4405
|
-
function createMemoryProvider(provider, store, baseDir, agent) {
|
|
4536
|
+
function createMemoryProvider(provider, store, baseDir, agent, openclawFacts) {
|
|
4406
4537
|
if (provider === "none") return new NullMemory();
|
|
4407
4538
|
if (provider === "hermes") return new HermesMemoryProvider(baseDir ?? "~/.hermes");
|
|
4408
|
-
if (provider === "openclaw") return new OpenClawMemoryProvider(store, baseDir ?? "~/.openclaw", agent ?? "");
|
|
4539
|
+
if (provider === "openclaw") return new OpenClawMemoryProvider(store, baseDir ?? "~/.openclaw", agent ?? "", openclawFacts);
|
|
4409
4540
|
return new SecureComsLocalMemory(store);
|
|
4410
4541
|
}
|
|
4411
4542
|
|
|
@@ -4513,7 +4644,10 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
4513
4644
|
identityId: cfg.identityId,
|
|
4514
4645
|
cipherFor: () => new KeyedInboxCipher(deriveMlsStoreKey(seed))
|
|
4515
4646
|
});
|
|
4516
|
-
this.memory = createMemoryProvider(this.cfg.memoryProvider, this.store, this.cfg.memoryBaseDir, this.cfg.memoryAgent
|
|
4647
|
+
this.memory = createMemoryProvider(this.cfg.memoryProvider, this.store, this.cfg.memoryBaseDir, this.cfg.memoryAgent, {
|
|
4648
|
+
workspaceDir: this.cfg.memoryWorkspaceDir,
|
|
4649
|
+
factsCharBudget: this.cfg.memoryFactsCharBudget
|
|
4650
|
+
});
|
|
4517
4651
|
this.provider = new MlsGroupKeyProvider({
|
|
4518
4652
|
store: this.store,
|
|
4519
4653
|
backend: this.backend,
|
|
@@ -4593,7 +4727,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
4593
4727
|
const j = await res.json();
|
|
4594
4728
|
return String(j.attachment_id);
|
|
4595
4729
|
};
|
|
4596
|
-
this.attachmentsDirImpl = deps.attachmentsDir ??
|
|
4730
|
+
this.attachmentsDirImpl = deps.attachmentsDir ?? join6(dirname(cfg.storePath), "attachments");
|
|
4597
4731
|
this.action = {
|
|
4598
4732
|
begin: (channelId) => this.actionBegin(channelId),
|
|
4599
4733
|
start: (opts) => this.actionStart(opts),
|
|
@@ -6120,13 +6254,13 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
6120
6254
|
};
|
|
6121
6255
|
|
|
6122
6256
|
// src/config.ts
|
|
6123
|
-
import { readFileSync as
|
|
6124
|
-
import { dirname as dirname2, join as
|
|
6257
|
+
import { readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
6258
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
6125
6259
|
var REQUIRED = ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
|
|
6126
6260
|
function loadConfig(opts) {
|
|
6127
|
-
const raw =
|
|
6261
|
+
const raw = readFileSync5(opts.credentialPath, "utf8");
|
|
6128
6262
|
try {
|
|
6129
|
-
const mode =
|
|
6263
|
+
const mode = statSync2(opts.credentialPath).mode & 511;
|
|
6130
6264
|
if (mode & 63) process.stderr.write(`[bridge] WARNING: credential file ${opts.credentialPath} permission ${mode.toString(8)} is not 0600 \u2014 tighten it (chmod 600).
|
|
6131
6265
|
`);
|
|
6132
6266
|
} catch {
|
|
@@ -6138,7 +6272,7 @@ function loadConfig(opts) {
|
|
|
6138
6272
|
throw new Error("credential file is not valid JSON");
|
|
6139
6273
|
}
|
|
6140
6274
|
for (const k of REQUIRED) if (typeof json2[k] !== "string" || !json2[k]) throw new Error(`credential file missing required field: ${k}`);
|
|
6141
|
-
const storePath = opts.storePath ??
|
|
6275
|
+
const storePath = opts.storePath ?? join7(dirname2(opts.credentialPath), "bridge-state.db");
|
|
6142
6276
|
const agentName = typeof json2.agent_name === "string" && json2.agent_name ? json2.agent_name : typeof json2.display_name === "string" && json2.display_name ? json2.display_name : void 0;
|
|
6143
6277
|
const rateLimitCapacity = typeof json2.rate_limit_capacity === "number" ? json2.rate_limit_capacity : 20;
|
|
6144
6278
|
const rateLimitRefillPerMinute = typeof json2.rate_limit_refill_per_minute === "number" ? json2.rate_limit_refill_per_minute : 20;
|
|
@@ -6146,6 +6280,8 @@ function loadConfig(opts) {
|
|
|
6146
6280
|
let memoryProvider;
|
|
6147
6281
|
let memoryBaseDir;
|
|
6148
6282
|
let memoryAgent;
|
|
6283
|
+
let memoryWorkspaceDir;
|
|
6284
|
+
let memoryFactsCharBudget;
|
|
6149
6285
|
if (memProvRaw === "none") {
|
|
6150
6286
|
memoryProvider = "none";
|
|
6151
6287
|
} else if (memProvRaw === "hermes") {
|
|
@@ -6159,6 +6295,10 @@ function loadConfig(opts) {
|
|
|
6159
6295
|
memoryBaseDir = typeof bd === "string" && bd ? bd : "~/.openclaw";
|
|
6160
6296
|
const ag = oc?.agent;
|
|
6161
6297
|
memoryAgent = typeof ag === "string" && ag ? ag : void 0;
|
|
6298
|
+
const wd = oc?.workspace_dir;
|
|
6299
|
+
memoryWorkspaceDir = typeof wd === "string" && wd ? wd : void 0;
|
|
6300
|
+
const fb = oc?.facts_char_budget;
|
|
6301
|
+
memoryFactsCharBudget = typeof fb === "number" && Number.isInteger(fb) && fb >= 0 ? fb : void 0;
|
|
6162
6302
|
} else {
|
|
6163
6303
|
memoryProvider = "securecoms";
|
|
6164
6304
|
}
|
|
@@ -6175,7 +6315,9 @@ function loadConfig(opts) {
|
|
|
6175
6315
|
rateLimitRefillPerMinute,
|
|
6176
6316
|
memoryProvider,
|
|
6177
6317
|
memoryBaseDir,
|
|
6178
|
-
memoryAgent
|
|
6318
|
+
memoryAgent,
|
|
6319
|
+
memoryWorkspaceDir,
|
|
6320
|
+
memoryFactsCharBudget
|
|
6179
6321
|
};
|
|
6180
6322
|
}
|
|
6181
6323
|
function arg(argv, flag) {
|
|
@@ -6219,11 +6361,11 @@ import { z } from "zod";
|
|
|
6219
6361
|
|
|
6220
6362
|
// src/auth.ts
|
|
6221
6363
|
import { randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
6222
|
-
import { existsSync, readFileSync as
|
|
6364
|
+
import { existsSync, readFileSync as readFileSync6, writeFileSync } from "node:fs";
|
|
6223
6365
|
function resolveToken(opts) {
|
|
6224
6366
|
if (opts.token) return opts.token;
|
|
6225
6367
|
const f = opts.tokenFile;
|
|
6226
|
-
if (f && existsSync(f)) return
|
|
6368
|
+
if (f && existsSync(f)) return readFileSync6(f, "utf8").trim();
|
|
6227
6369
|
const tok = randomBytes3(32).toString("base64url");
|
|
6228
6370
|
if (f) writeFileSync(f, tok, { mode: 384 });
|
|
6229
6371
|
return tok;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { MemoryProvider } from "./provider.js";
|
|
2
2
|
import type { SqliteMlsStateStore, MemoryRecordInput, MemoryContextResult } from "@agentvault/connect-mls-store";
|
|
3
|
+
export interface OpenClawFactsOptions {
|
|
4
|
+
workspaceDir?: string;
|
|
5
|
+
factsCharBudget?: number;
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
8
|
* MemoryProvider for an OpenClaw-hosted agent (Cortina). context() merges
|
|
5
9
|
* OpenClaw's own text history (read-only, plain session .jsonl) with the
|
|
@@ -12,9 +16,14 @@ export declare class OpenClawMemoryProvider implements MemoryProvider {
|
|
|
12
16
|
private readonly store;
|
|
13
17
|
private readonly baseDir;
|
|
14
18
|
private readonly agent;
|
|
19
|
+
private readonly factsOpts?;
|
|
15
20
|
private noSession;
|
|
16
21
|
private readFailed;
|
|
17
|
-
|
|
22
|
+
private factsMissing;
|
|
23
|
+
private factsReadFailed;
|
|
24
|
+
private factsTruncated;
|
|
25
|
+
private factsChars;
|
|
26
|
+
constructor(store: SqliteMlsStateStore, baseDir: string, agent: string, factsOpts?: OpenClawFactsOptions | undefined);
|
|
18
27
|
record(input: MemoryRecordInput): Promise<{
|
|
19
28
|
seq: number;
|
|
20
29
|
deduped: boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Spec D2 constants — pinned so tests are deterministic. "Chars" = UTF-16 code units. */
|
|
2
|
+
export declare const DEFAULT_FACTS_BUDGET = 8000;
|
|
3
|
+
export declare const MEMORY_MD_CAP = 6000;
|
|
4
|
+
export declare const MIN_FRAGMENT = 200;
|
|
5
|
+
export declare const MAX_SOURCE_BYTES: number;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the agent's OpenClaw workspace dir (spec D4). Ladder, first hit wins:
|
|
8
|
+
* 1. explicit override (credential workspace_dir) — operator beats everything;
|
|
9
|
+
* 2. openclaw.json, resolved the way OpenClaw itself would:
|
|
10
|
+
* 2a. agents.list entry with id===agent and a NON-EMPTY string workspace (verbatim,
|
|
11
|
+
* never case-transformed — the live config declares "workspace-cortina" for an
|
|
12
|
+
* on-disk "workspace-Cortina" and works only because APFS is case-insensitive);
|
|
13
|
+
* 2b. else agents.defaults.workspace when it is a non-empty string (covers main,
|
|
14
|
+
* whose live entry has the workspace key ABSENT, and named agents w/o one);
|
|
15
|
+
* 3. derivation, LAST resort (openclaw.json missing/malformed/silent):
|
|
16
|
+
* main/"" → <base>/workspace, else <base>/workspace-<agent> verbatim.
|
|
17
|
+
* Empty agent is treated as "main" throughout (the factory passes agent ?? "").
|
|
18
|
+
* Total: always returns a path; existence is checked at read time, fail-safe.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveWorkspaceDir(baseDir: string, agent: string, override?: string): string;
|
|
21
|
+
export interface WorkspaceFactsResult {
|
|
22
|
+
/** 0..3 provenance-prefixed facts: MEMORY.md first, then dailies newest-first. */
|
|
23
|
+
facts: string[];
|
|
24
|
+
/** True when the budget clipped or dropped any source (includes the >1MB skip). */
|
|
25
|
+
truncated: boolean;
|
|
26
|
+
/** True when the resolved workspace yielded zero usable sources. False on budget-0 kill switch. */
|
|
27
|
+
missing: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the workspace facts (spec D1-D3). READ-ONLY, total: never throws for any
|
|
31
|
+
* filesystem state — absence degrades to fewer/zero facts. Only MEMORY.md and
|
|
32
|
+
* memory/\d{4}-\d{2}-\d{2}\.md under the resolved dir are ever opened.
|
|
33
|
+
* Budget accounting is content-only; prefixes and markers are exempt (audit M2).
|
|
34
|
+
*/
|
|
35
|
+
export declare function readWorkspaceFacts(baseDir: string, agent: string, opts?: {
|
|
36
|
+
workspaceDir?: string;
|
|
37
|
+
charBudget?: number;
|
|
38
|
+
}): WorkspaceFactsResult;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SqliteMlsStateStore, MemoryRecordInput, MemoryContextResult } from "@agentvault/connect-mls-store";
|
|
2
|
+
import type { OpenClawFactsOptions } from "./openclaw-provider.js";
|
|
2
3
|
export interface MemoryProvider {
|
|
3
4
|
record(input: MemoryRecordInput): Promise<{
|
|
4
5
|
seq: number;
|
|
@@ -26,4 +27,4 @@ export declare class NullMemory implements MemoryProvider {
|
|
|
26
27
|
}>;
|
|
27
28
|
context(): Promise<MemoryContextResult>;
|
|
28
29
|
}
|
|
29
|
-
export declare function createMemoryProvider(provider: "securecoms" | "none" | "hermes" | "openclaw", store: SqliteMlsStateStore, baseDir?: string, agent?: string): MemoryProvider;
|
|
30
|
+
export declare function createMemoryProvider(provider: "securecoms" | "none" | "hermes" | "openclaw", store: SqliteMlsStateStore, baseDir?: string, agent?: string, openclawFacts?: OpenClawFactsOptions): MemoryProvider;
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/connectors/hermes/tests/__pycache__/test_adapter_wiring.cpython-311-pytest-8.4.0.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/connectors/hermes/tests/__pycache__/test_securecoms_gate.cpython-311-pytest-8.4.0.pyc
DELETED
|
Binary file
|