@remnic/plugin-openclaw 1.0.21 → 1.0.22
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 +168 -7
- package/openclaw.plugin.json +13 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -667,9 +667,12 @@ function parseConfig(raw) {
|
|
|
667
667
|
} else {
|
|
668
668
|
cfg = baseCfg;
|
|
669
669
|
}
|
|
670
|
+
const modelSource = cfg.modelSource === "gateway" ? "gateway" : "plugin";
|
|
670
671
|
let apiKey;
|
|
671
672
|
if (typeof cfg.openaiApiKey === "string" && cfg.openaiApiKey.length > 0) {
|
|
672
673
|
apiKey = resolveEnvVars(cfg.openaiApiKey);
|
|
674
|
+
} else if (modelSource === "gateway") {
|
|
675
|
+
apiKey = void 0;
|
|
673
676
|
} else {
|
|
674
677
|
apiKey = readEnvVar("OPENAI_API_KEY");
|
|
675
678
|
}
|
|
@@ -1594,7 +1597,7 @@ function parseConfig(raw) {
|
|
|
1594
1597
|
// Gateway config (passed from index.ts for fallback AI)
|
|
1595
1598
|
gatewayConfig: cfg.gatewayConfig,
|
|
1596
1599
|
// Gateway model source (v9.2) — route LLM calls through gateway agent model chain
|
|
1597
|
-
modelSource
|
|
1600
|
+
modelSource,
|
|
1598
1601
|
gatewayAgentId: typeof cfg.gatewayAgentId === "string" && cfg.gatewayAgentId.length > 0 ? cfg.gatewayAgentId : "",
|
|
1599
1602
|
fastGatewayAgentId: typeof cfg.fastGatewayAgentId === "string" && cfg.fastGatewayAgentId.length > 0 ? cfg.fastGatewayAgentId : "",
|
|
1600
1603
|
// v3.0 namespaces (default off)
|
|
@@ -9070,6 +9073,9 @@ var NoopSearchBackend = class {
|
|
|
9070
9073
|
}
|
|
9071
9074
|
async updateCollection(_collection, _execution) {
|
|
9072
9075
|
}
|
|
9076
|
+
updatesAllCollections() {
|
|
9077
|
+
return false;
|
|
9078
|
+
}
|
|
9073
9079
|
async embed() {
|
|
9074
9080
|
}
|
|
9075
9081
|
async embedCollection(_collection) {
|
|
@@ -11359,6 +11365,9 @@ ${stderr}`.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
|
11359
11365
|
execution?.signal
|
|
11360
11366
|
);
|
|
11361
11367
|
}
|
|
11368
|
+
updatesAllCollections() {
|
|
11369
|
+
return true;
|
|
11370
|
+
}
|
|
11362
11371
|
async runUpdateForCollection(collection, options, signal) {
|
|
11363
11372
|
if (this.available === false) {
|
|
11364
11373
|
if (options.strict) {
|
|
@@ -23198,6 +23207,9 @@ var TURN_REFERENCE_WINDOW_RADIUS = 0;
|
|
|
23198
23207
|
var LEXICAL_CUE_WINDOW_RADIUS = 1;
|
|
23199
23208
|
var LEXICAL_CUE_SEARCH_LIMIT = 3;
|
|
23200
23209
|
var LEXICAL_CUE_MAX_TOKENS = 400;
|
|
23210
|
+
var CONTENT_LABEL_SEARCH_LIMIT = 64;
|
|
23211
|
+
var CONTENT_LABEL_MAX_TOKENS = 2e3;
|
|
23212
|
+
var CONTENT_LABEL_MAX_PAIRED_WINDOWS_PER_REFERENCE = 1;
|
|
23201
23213
|
var LATEST_STATE_CUES = /* @__PURE__ */ new Set([
|
|
23202
23214
|
"as of",
|
|
23203
23215
|
"currently",
|
|
@@ -23419,6 +23431,13 @@ async function collectTurnReferenceEvidence(options) {
|
|
|
23419
23431
|
if (references.length === 0) {
|
|
23420
23432
|
return;
|
|
23421
23433
|
}
|
|
23434
|
+
await collectContentLabelReferenceEvidence({
|
|
23435
|
+
engine: options.engine,
|
|
23436
|
+
sessionId: options.sessionId,
|
|
23437
|
+
references,
|
|
23438
|
+
evidenceItems: options.evidenceItems,
|
|
23439
|
+
seenTurns: options.seenTurns
|
|
23440
|
+
});
|
|
23422
23441
|
const windows = /* @__PURE__ */ new Map();
|
|
23423
23442
|
for (const reference of references) {
|
|
23424
23443
|
for (const center of candidateTurnIndexesForReference(reference)) {
|
|
@@ -23447,6 +23466,144 @@ async function collectTurnReferenceEvidence(options) {
|
|
|
23447
23466
|
);
|
|
23448
23467
|
}
|
|
23449
23468
|
}
|
|
23469
|
+
async function collectContentLabelReferenceEvidence(options) {
|
|
23470
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
23471
|
+
for (const reference of options.references) {
|
|
23472
|
+
if (reference.includeDirectTurn) {
|
|
23473
|
+
continue;
|
|
23474
|
+
}
|
|
23475
|
+
const hits = await searchReferenceContentLabels(
|
|
23476
|
+
options.engine,
|
|
23477
|
+
reference.number,
|
|
23478
|
+
options.sessionId
|
|
23479
|
+
);
|
|
23480
|
+
if (hits.length === 0) {
|
|
23481
|
+
continue;
|
|
23482
|
+
}
|
|
23483
|
+
resolved.add(reference.number);
|
|
23484
|
+
let appendedWindows = 0;
|
|
23485
|
+
for (const hit of hits) {
|
|
23486
|
+
if (appendedWindows >= CONTENT_LABEL_MAX_PAIRED_WINDOWS_PER_REFERENCE) {
|
|
23487
|
+
break;
|
|
23488
|
+
}
|
|
23489
|
+
const { fromTurn, toTurn } = contentLabelEvidenceWindow(hit);
|
|
23490
|
+
const expanded = await options.engine.expandContext(
|
|
23491
|
+
hit.session_id,
|
|
23492
|
+
fromTurn,
|
|
23493
|
+
toTurn,
|
|
23494
|
+
CONTENT_LABEL_MAX_TOKENS
|
|
23495
|
+
);
|
|
23496
|
+
if (!expandedHasPairedTrajectoryLabels(expanded, reference.number)) {
|
|
23497
|
+
continue;
|
|
23498
|
+
}
|
|
23499
|
+
if (expanded.length === 0) {
|
|
23500
|
+
appendEvidenceItem(options.evidenceItems, options.seenTurns, {
|
|
23501
|
+
id: `${hit.session_id}:${hit.turn_index}`,
|
|
23502
|
+
sessionId: hit.session_id,
|
|
23503
|
+
turnIndex: hit.turn_index,
|
|
23504
|
+
role: hit.role,
|
|
23505
|
+
content: hit.content
|
|
23506
|
+
});
|
|
23507
|
+
continue;
|
|
23508
|
+
}
|
|
23509
|
+
appendExpandedEvidence(
|
|
23510
|
+
options.evidenceItems,
|
|
23511
|
+
options.seenTurns,
|
|
23512
|
+
hit.session_id,
|
|
23513
|
+
expanded
|
|
23514
|
+
);
|
|
23515
|
+
appendedWindows += 1;
|
|
23516
|
+
}
|
|
23517
|
+
}
|
|
23518
|
+
return resolved;
|
|
23519
|
+
}
|
|
23520
|
+
async function searchReferenceContentLabels(engine, referenceNumber, sessionId) {
|
|
23521
|
+
const hits = /* @__PURE__ */ new Map();
|
|
23522
|
+
for (const labelKind of ["action", "observation"]) {
|
|
23523
|
+
const label = labelKind === "action" ? "Action" : "Observation";
|
|
23524
|
+
for (const query of [`[${label} ${referenceNumber}]`, `${label} ${referenceNumber}`]) {
|
|
23525
|
+
const results = await engine.searchContextFull(
|
|
23526
|
+
query,
|
|
23527
|
+
CONTENT_LABEL_SEARCH_LIMIT,
|
|
23528
|
+
sessionId
|
|
23529
|
+
);
|
|
23530
|
+
for (const result of results) {
|
|
23531
|
+
if (!isReferenceLabelRole(result.role, labelKind) || !contentHasReferenceLabel(result.content, labelKind, referenceNumber)) {
|
|
23532
|
+
continue;
|
|
23533
|
+
}
|
|
23534
|
+
hits.set(`${result.session_id}:${result.turn_index}:${labelKind}`, {
|
|
23535
|
+
turn_index: result.turn_index,
|
|
23536
|
+
role: result.role,
|
|
23537
|
+
content: result.content,
|
|
23538
|
+
session_id: result.session_id,
|
|
23539
|
+
labelKind
|
|
23540
|
+
});
|
|
23541
|
+
}
|
|
23542
|
+
}
|
|
23543
|
+
}
|
|
23544
|
+
const numericCandidates = candidateTurnIndexesForReference({
|
|
23545
|
+
number: referenceNumber,
|
|
23546
|
+
includeDirectTurn: false
|
|
23547
|
+
});
|
|
23548
|
+
return [...hits.values()].sort((left, right) => {
|
|
23549
|
+
const sessionOrder = left.session_id.localeCompare(right.session_id);
|
|
23550
|
+
if (sessionOrder !== 0) {
|
|
23551
|
+
return sessionOrder;
|
|
23552
|
+
}
|
|
23553
|
+
const leftDistance = nearestTurnDistance(left.turn_index, numericCandidates);
|
|
23554
|
+
const rightDistance = nearestTurnDistance(right.turn_index, numericCandidates);
|
|
23555
|
+
if (leftDistance !== rightDistance) {
|
|
23556
|
+
return leftDistance - rightDistance;
|
|
23557
|
+
}
|
|
23558
|
+
return left.turn_index - right.turn_index || left.labelKind.localeCompare(right.labelKind);
|
|
23559
|
+
});
|
|
23560
|
+
}
|
|
23561
|
+
function nearestTurnDistance(turnIndex, candidates) {
|
|
23562
|
+
let nearest = Number.POSITIVE_INFINITY;
|
|
23563
|
+
for (const candidate of candidates) {
|
|
23564
|
+
nearest = Math.min(nearest, Math.abs(turnIndex - candidate));
|
|
23565
|
+
}
|
|
23566
|
+
return nearest;
|
|
23567
|
+
}
|
|
23568
|
+
function contentLabelEvidenceWindow(hit) {
|
|
23569
|
+
if (hit.labelKind === "action") {
|
|
23570
|
+
return {
|
|
23571
|
+
fromTurn: Math.max(0, hit.turn_index - 1),
|
|
23572
|
+
toTurn: hit.turn_index + 1
|
|
23573
|
+
};
|
|
23574
|
+
}
|
|
23575
|
+
return {
|
|
23576
|
+
fromTurn: Math.max(0, hit.turn_index - 1),
|
|
23577
|
+
toTurn: hit.turn_index
|
|
23578
|
+
};
|
|
23579
|
+
}
|
|
23580
|
+
function contentHasReferenceLabel(content, labelKind, referenceNumber) {
|
|
23581
|
+
const label = labelKind === "action" ? "Action" : "Observation";
|
|
23582
|
+
const escapedNumber = String(referenceNumber).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23583
|
+
return new RegExp(
|
|
23584
|
+
`^\\s*\\[\\s*${label}\\s+${escapedNumber}\\s*\\]\\s*(?::\\s*)?`,
|
|
23585
|
+
"i"
|
|
23586
|
+
).test(content);
|
|
23587
|
+
}
|
|
23588
|
+
function isReferenceLabelRole(role, labelKind) {
|
|
23589
|
+
if (labelKind === "action") {
|
|
23590
|
+
return role === "user";
|
|
23591
|
+
}
|
|
23592
|
+
return role === "assistant";
|
|
23593
|
+
}
|
|
23594
|
+
function expandedHasPairedTrajectoryLabels(expanded, referenceNumber) {
|
|
23595
|
+
let hasAction = false;
|
|
23596
|
+
let hasObservation = false;
|
|
23597
|
+
for (const message of expanded) {
|
|
23598
|
+
if (isReferenceLabelRole(message.role, "action") && contentHasReferenceLabel(message.content, "action", referenceNumber)) {
|
|
23599
|
+
hasAction = true;
|
|
23600
|
+
}
|
|
23601
|
+
if (isReferenceLabelRole(message.role, "observation") && contentHasReferenceLabel(message.content, "observation", referenceNumber)) {
|
|
23602
|
+
hasObservation = true;
|
|
23603
|
+
}
|
|
23604
|
+
}
|
|
23605
|
+
return hasAction && hasObservation;
|
|
23606
|
+
}
|
|
23450
23607
|
async function collectLexicalCueEvidence(options) {
|
|
23451
23608
|
const cues = collectLexicalCues(options.query, {
|
|
23452
23609
|
includeBenchmarkAnchorCues: options.includeBenchmarkAnchorCues,
|
|
@@ -32474,15 +32631,19 @@ var NamespaceSearchRouter = class {
|
|
|
32474
32631
|
*/
|
|
32475
32632
|
async updateNamespaces(namespaces, execution) {
|
|
32476
32633
|
const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));
|
|
32477
|
-
const
|
|
32634
|
+
const eligible = (await Promise.all(
|
|
32478
32635
|
unique.map(async (namespace) => {
|
|
32479
32636
|
const record = await this.backendRecordFor(namespace);
|
|
32480
|
-
|
|
32481
|
-
await record.backend.update(execution);
|
|
32482
|
-
return 1;
|
|
32637
|
+
return record.available && record.collectionState !== "missing" ? record : null;
|
|
32483
32638
|
})
|
|
32484
|
-
);
|
|
32485
|
-
|
|
32639
|
+
)).filter((record) => record !== null);
|
|
32640
|
+
const globalRecord = eligible.find((record) => record.backend.updatesAllCollections?.() === true);
|
|
32641
|
+
const scopedRecords = globalRecord ? eligible.filter((record) => record.backend.updatesAllCollections?.() !== true) : eligible;
|
|
32642
|
+
await Promise.all([
|
|
32643
|
+
globalRecord ? globalRecord.backend.update(execution) : Promise.resolve(),
|
|
32644
|
+
...scopedRecords.map((record) => record.backend.update(execution))
|
|
32645
|
+
]);
|
|
32646
|
+
return (globalRecord ? 1 : 0) + scopedRecords.length;
|
|
32486
32647
|
}
|
|
32487
32648
|
async embedNamespaces(namespaces) {
|
|
32488
32649
|
const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-remnic",
|
|
3
3
|
"name": "Remnic OpenClaw Plugin",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.22",
|
|
5
5
|
"kind": "memory",
|
|
6
6
|
"description": "Local semantic memory for OpenClaw. Requires plugins.slots.memory set to this plugin id for hooks to fire.",
|
|
7
7
|
"setup": {
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"provider": "openai",
|
|
29
29
|
"method": "api-key",
|
|
30
30
|
"choiceId": "remnic-openai-api-key",
|
|
31
|
-
"choiceLabel": "OpenAI API key for Remnic
|
|
32
|
-
"choiceHint": "
|
|
31
|
+
"choiceLabel": "Optional OpenAI API key for Remnic plugin-mode extraction",
|
|
32
|
+
"choiceHint": "Not needed when Remnic uses the OpenClaw gateway model source. Set only if you intentionally use plugin mode with OpenAI or an OpenAI-compatible endpoint.",
|
|
33
33
|
"groupId": "remnic-memory",
|
|
34
34
|
"groupLabel": "Remnic memory",
|
|
35
35
|
"optionKey": "openaiApiKey",
|
|
36
36
|
"cliFlag": "--openai-api-key",
|
|
37
37
|
"cliOption": "--openai-api-key <key>",
|
|
38
|
-
"cliDescription": "OpenAI API key used by Remnic
|
|
38
|
+
"cliDescription": "Optional OpenAI API key used by Remnic plugin-mode extraction, consolidation, and embedding flows.",
|
|
39
39
|
"onboardingScopes": [
|
|
40
40
|
"text-inference"
|
|
41
41
|
]
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"properties": {
|
|
108
108
|
"openaiApiKey": {
|
|
109
109
|
"type": "string",
|
|
110
|
-
"description": "OpenAI API key (or set OPENAI_API_KEY env var). Remnic may send conversation and memory content to OpenAI or the configured OpenAI-compatible endpoint for extraction, consolidation, summarization, and embeddings."
|
|
110
|
+
"description": "Optional OpenAI API key for plugin mode (or set OPENAI_API_KEY env var). Ignored by default gateway-mode installs; in plugin mode, Remnic may send conversation and memory content to OpenAI or the configured OpenAI-compatible endpoint for extraction, consolidation, summarization, and embeddings."
|
|
111
111
|
},
|
|
112
112
|
"openaiBaseUrl": {
|
|
113
113
|
"type": "string",
|
|
@@ -2853,12 +2853,12 @@
|
|
|
2853
2853
|
},
|
|
2854
2854
|
"modelSource": {
|
|
2855
2855
|
"type": "string",
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2856
|
+
"enum": [
|
|
2857
|
+
"plugin",
|
|
2858
|
+
"gateway"
|
|
2859
|
+
],
|
|
2860
|
+
"default": "gateway",
|
|
2861
|
+
"description": "LLM source: 'gateway' delegates to a gateway agent's model chain (agents.list[]); 'plugin' uses Engram's own openai/localLlm config."
|
|
2862
2862
|
},
|
|
2863
2863
|
"gatewayAgentId": {
|
|
2864
2864
|
"type": "string",
|
|
@@ -4593,7 +4593,7 @@
|
|
|
4593
4593
|
"label": "OpenAI API Key",
|
|
4594
4594
|
"sensitive": true,
|
|
4595
4595
|
"placeholder": "sk-...",
|
|
4596
|
-
"help": "API key for
|
|
4596
|
+
"help": "Optional API key for plugin mode only. Not needed when Model Source is gateway."
|
|
4597
4597
|
},
|
|
4598
4598
|
"openaiBaseUrl": {
|
|
4599
4599
|
"label": "OpenAI Base URL",
|
|
@@ -5041,7 +5041,7 @@
|
|
|
5041
5041
|
},
|
|
5042
5042
|
"modelSource": {
|
|
5043
5043
|
"label": "Model Source",
|
|
5044
|
-
"help": "Route LLM calls through the gateway's agent model chain instead of Engram's own config. When set to 'gateway', localLlm and openai settings are ignored."
|
|
5044
|
+
"help": "Route LLM calls through the gateway's agent model chain instead of Engram's own config. Default for OpenClaw installs. When set to 'gateway', localLlm and openai settings are ignored."
|
|
5045
5045
|
},
|
|
5046
5046
|
"gatewayAgentId": {
|
|
5047
5047
|
"label": "Gateway Agent ID",
|