@remnic/plugin-openclaw 9.25.7 → 9.27.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 +352 -11
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5275,6 +5275,7 @@ function resolveRemnicOpenClawPluginEntry(raw, preferredId) {
|
|
|
5275
5275
|
import path4 from "path";
|
|
5276
5276
|
import { renderMemoryContextPrompt } from "@remnic/core";
|
|
5277
5277
|
import { log as log2 } from "@remnic/core/logger";
|
|
5278
|
+
import { SESSION_NAMESPACE_BINDING_MAX_ENTRIES, SESSION_NAMESPACE_BINDING_MAX_NAMESPACES, SESSION_NAMESPACE_BINDING_MAX_NAMESPACE_LENGTH, createFileSessionNamespaceBindingStore } from "@remnic/core/session-namespace-bindings";
|
|
5278
5279
|
import { createFileToggleStore } from "@remnic/core/session-toggles";
|
|
5279
5280
|
|
|
5280
5281
|
// src/bridge.ts
|
|
@@ -5605,6 +5606,7 @@ function extractTextContent(msg) {
|
|
|
5605
5606
|
}
|
|
5606
5607
|
|
|
5607
5608
|
// src/delegate-runtime.ts
|
|
5609
|
+
var DELEGATE_BATCH_FLUSH_CACHE_TTL_MS = 3e4;
|
|
5608
5610
|
var DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS = [
|
|
5609
5611
|
"recall",
|
|
5610
5612
|
"observe",
|
|
@@ -5668,6 +5670,30 @@ async function postJson(target, serviceId, pathname, body, timeoutMs) {
|
|
|
5668
5670
|
const parsed = await res.json().catch(() => null);
|
|
5669
5671
|
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
5670
5672
|
}
|
|
5673
|
+
async function getJson(target, serviceId, pathname, timeoutMs) {
|
|
5674
|
+
const headers = {};
|
|
5675
|
+
const auth = target.resolveAuthToken();
|
|
5676
|
+
if (auth.token) headers.Authorization = `Bearer ${auth.token}`;
|
|
5677
|
+
const res = await fetch(daemonUrl(target, pathname), {
|
|
5678
|
+
headers,
|
|
5679
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
5680
|
+
});
|
|
5681
|
+
if (!res.ok) {
|
|
5682
|
+
if (res.status === 401 || res.status === 403) {
|
|
5683
|
+
const status = res.status === 401 ? 401 : 403;
|
|
5684
|
+
await res.body?.cancel();
|
|
5685
|
+
reportDaemonAuthorizationFailure(serviceId, pathname, status, auth.source);
|
|
5686
|
+
return { status: res.status, body: null };
|
|
5687
|
+
}
|
|
5688
|
+
await res.body?.cancel();
|
|
5689
|
+
return { status: res.status, body: null };
|
|
5690
|
+
}
|
|
5691
|
+
const parsed = await res.json().catch(() => null);
|
|
5692
|
+
return {
|
|
5693
|
+
status: res.status,
|
|
5694
|
+
body: typeof parsed === "object" && parsed !== null ? parsed : null
|
|
5695
|
+
};
|
|
5696
|
+
}
|
|
5671
5697
|
function sessionKeyFrom(event, ctx) {
|
|
5672
5698
|
const fromCtx = ctx?.sessionKey;
|
|
5673
5699
|
if (typeof fromCtx === "string" && fromCtx.length > 0) return fromCtx;
|
|
@@ -5675,6 +5701,13 @@ function sessionKeyFrom(event, ctx) {
|
|
|
5675
5701
|
if (typeof fromEvent === "string" && fromEvent.length > 0) return fromEvent;
|
|
5676
5702
|
return "default";
|
|
5677
5703
|
}
|
|
5704
|
+
function lifecycleSessionKeyFrom(event, ctx) {
|
|
5705
|
+
const fromEvent = event?.sessionKey;
|
|
5706
|
+
if (fromEvent !== void 0) {
|
|
5707
|
+
return typeof fromEvent === "string" && fromEvent.length > 0 ? fromEvent : void 0;
|
|
5708
|
+
}
|
|
5709
|
+
return sessionKeyFrom(event, ctx);
|
|
5710
|
+
}
|
|
5678
5711
|
function recallQueryFrom(event) {
|
|
5679
5712
|
let prompt = typeof event.prompt === "string" ? event.prompt : void 0;
|
|
5680
5713
|
if ((!prompt || prompt.length < 5) && Array.isArray(event.messages)) {
|
|
@@ -5699,7 +5732,67 @@ function cwdFrom(event, ctx, fallback) {
|
|
|
5699
5732
|
return fallback;
|
|
5700
5733
|
}
|
|
5701
5734
|
function withNamespace(namespace, body) {
|
|
5702
|
-
return namespace
|
|
5735
|
+
return namespace ? { ...body, namespace } : body;
|
|
5736
|
+
}
|
|
5737
|
+
function explicitSessionNamespaceFrom(sessionKey, event, ctx) {
|
|
5738
|
+
const eventSessionKey = typeof event.sessionKey === "string" ? event.sessionKey : void 0;
|
|
5739
|
+
const ctxSessionKey = typeof ctx.sessionKey === "string" ? ctx.sessionKey : void 0;
|
|
5740
|
+
const sources = eventSessionKey === sessionKey ? [event, ctx] : ctxSessionKey === sessionKey ? [ctx, event] : [ctx, event];
|
|
5741
|
+
for (const source of sources) {
|
|
5742
|
+
const sourceSessionKey = typeof source.sessionKey === "string" ? source.sessionKey : void 0;
|
|
5743
|
+
if (sourceSessionKey !== sessionKey) continue;
|
|
5744
|
+
const runtime = source.runtime;
|
|
5745
|
+
if (typeof runtime !== "object" || runtime === null) continue;
|
|
5746
|
+
const agent = runtime.agent;
|
|
5747
|
+
if (typeof agent !== "object" || agent === null) continue;
|
|
5748
|
+
const session = agent.session;
|
|
5749
|
+
if (typeof session !== "object" || session === null) continue;
|
|
5750
|
+
const namespace = session.namespace;
|
|
5751
|
+
if (namespace !== void 0 && typeof namespace !== "string") {
|
|
5752
|
+
throw new Error("delegate session namespace metadata must be a string");
|
|
5753
|
+
}
|
|
5754
|
+
return { namespace: typeof namespace === "string" ? namespace.trim() || void 0 : void 0 };
|
|
5755
|
+
}
|
|
5756
|
+
return void 0;
|
|
5757
|
+
}
|
|
5758
|
+
async function rememberedNamespacesFor(sessionKey, namespaceBindings) {
|
|
5759
|
+
return namespaceBindings.namespacesFor(sessionKey);
|
|
5760
|
+
}
|
|
5761
|
+
async function rememberNamespace(sessionKey, namespace, namespaceBindings) {
|
|
5762
|
+
if (namespace.length > SESSION_NAMESPACE_BINDING_MAX_NAMESPACE_LENGTH) {
|
|
5763
|
+
throw new Error(
|
|
5764
|
+
`delegate session namespace exceeds the daemon limit of ${SESSION_NAMESPACE_BINDING_MAX_NAMESPACE_LENGTH} characters`
|
|
5765
|
+
);
|
|
5766
|
+
}
|
|
5767
|
+
try {
|
|
5768
|
+
await namespaceBindings.remember(sessionKey, namespace);
|
|
5769
|
+
} catch (err) {
|
|
5770
|
+
log2.warn(`delegate namespace binding persistence failed: ${String(err)}`);
|
|
5771
|
+
throw err;
|
|
5772
|
+
}
|
|
5773
|
+
}
|
|
5774
|
+
async function sessionNamespaceFrom(sessionKey, event, ctx, fallback, namespaceBindings) {
|
|
5775
|
+
const explicit = explicitSessionNamespaceFrom(sessionKey, event, ctx);
|
|
5776
|
+
if (explicit !== void 0) {
|
|
5777
|
+
await rememberNamespace(sessionKey, explicit.namespace ?? "", namespaceBindings);
|
|
5778
|
+
return explicit.namespace;
|
|
5779
|
+
}
|
|
5780
|
+
const remembered = await rememberedNamespacesFor(sessionKey, namespaceBindings);
|
|
5781
|
+
return remembered.length > 0 ? remembered.at(-1) || void 0 : fallback.trim() || void 0;
|
|
5782
|
+
}
|
|
5783
|
+
async function lifecycleSessionNamespacesFrom(sessionKey, event, ctx, fallback, namespaceBindings) {
|
|
5784
|
+
const explicit = explicitSessionNamespaceFrom(sessionKey, event, ctx);
|
|
5785
|
+
if (explicit !== void 0) {
|
|
5786
|
+
await rememberNamespace(sessionKey, explicit.namespace ?? "", namespaceBindings);
|
|
5787
|
+
}
|
|
5788
|
+
const remembered = await rememberedNamespacesFor(sessionKey, namespaceBindings);
|
|
5789
|
+
if (explicit !== void 0) {
|
|
5790
|
+
const explicitNamespace = explicit.namespace ?? "";
|
|
5791
|
+
const namespaces = remembered.includes(explicitNamespace) ? remembered : [...remembered, explicitNamespace];
|
|
5792
|
+
return namespaces.map((namespace) => namespace || void 0);
|
|
5793
|
+
}
|
|
5794
|
+
if (remembered.length > 0) return remembered.map((namespace) => namespace || void 0);
|
|
5795
|
+
return [fallback.trim() || void 0];
|
|
5703
5796
|
}
|
|
5704
5797
|
function readContextComposition(response, fallbackContext) {
|
|
5705
5798
|
const candidate = response.contextComposition;
|
|
@@ -5712,7 +5805,8 @@ function readContextComposition(response, fallbackContext) {
|
|
|
5712
5805
|
return { context: candidate.context };
|
|
5713
5806
|
}
|
|
5714
5807
|
function registerDelegateRuntime(api, options) {
|
|
5715
|
-
const { target, namespace } = options;
|
|
5808
|
+
const { target, namespace, namespaceBindings } = options;
|
|
5809
|
+
const now = options.now ?? Date.now;
|
|
5716
5810
|
if (options.passive) {
|
|
5717
5811
|
log2.info(
|
|
5718
5812
|
`[${options.serviceId}] bridge mode delegate: memory slot not owned \u2014 passive, no hooks registered`
|
|
@@ -5739,11 +5833,18 @@ function registerDelegateRuntime(api, options) {
|
|
|
5739
5833
|
return void 0;
|
|
5740
5834
|
}
|
|
5741
5835
|
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5836
|
+
const scopedNamespace = await sessionNamespaceFrom(
|
|
5837
|
+
sessionKey,
|
|
5838
|
+
event,
|
|
5839
|
+
ctx,
|
|
5840
|
+
namespace,
|
|
5841
|
+
namespaceBindings
|
|
5842
|
+
);
|
|
5742
5843
|
const response = await postJson(
|
|
5743
5844
|
target,
|
|
5744
5845
|
options.serviceId,
|
|
5745
5846
|
"/engram/v1/recall",
|
|
5746
|
-
withNamespace(
|
|
5847
|
+
withNamespace(scopedNamespace, {
|
|
5747
5848
|
query,
|
|
5748
5849
|
sessionKey,
|
|
5749
5850
|
mode: "auto",
|
|
@@ -5815,11 +5916,18 @@ function registerDelegateRuntime(api, options) {
|
|
|
5815
5916
|
if (turn.length === 0) return;
|
|
5816
5917
|
try {
|
|
5817
5918
|
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5919
|
+
const scopedNamespace = await sessionNamespaceFrom(
|
|
5920
|
+
sessionKey,
|
|
5921
|
+
event,
|
|
5922
|
+
ctx,
|
|
5923
|
+
namespace,
|
|
5924
|
+
namespaceBindings
|
|
5925
|
+
);
|
|
5818
5926
|
await postJson(
|
|
5819
5927
|
target,
|
|
5820
5928
|
options.serviceId,
|
|
5821
5929
|
"/engram/v1/observe",
|
|
5822
|
-
withNamespace(
|
|
5930
|
+
withNamespace(scopedNamespace, {
|
|
5823
5931
|
sessionKey,
|
|
5824
5932
|
messages: turn,
|
|
5825
5933
|
...cwd ? { cwd } : {},
|
|
@@ -5831,25 +5939,129 @@ function registerDelegateRuntime(api, options) {
|
|
|
5831
5939
|
log2.warn(`delegate observe failed: ${String(err)}`);
|
|
5832
5940
|
}
|
|
5833
5941
|
});
|
|
5942
|
+
let cachedBatchFlushSupport;
|
|
5943
|
+
let cachedBatchFlushSupportExpiresAt = 0;
|
|
5944
|
+
let supportsBatchFlushPromise;
|
|
5945
|
+
const invalidateCachedBatchFlushSupport = () => {
|
|
5946
|
+
cachedBatchFlushSupport = void 0;
|
|
5947
|
+
cachedBatchFlushSupportExpiresAt = 0;
|
|
5948
|
+
};
|
|
5949
|
+
const cacheBatchFlushSupport = (supported) => {
|
|
5950
|
+
cachedBatchFlushSupport = supported;
|
|
5951
|
+
cachedBatchFlushSupportExpiresAt = now() + DELEGATE_BATCH_FLUSH_CACHE_TTL_MS;
|
|
5952
|
+
};
|
|
5953
|
+
const supportsBatchFlush = (timeoutMs) => {
|
|
5954
|
+
if (cachedBatchFlushSupport !== void 0) {
|
|
5955
|
+
if (now() < cachedBatchFlushSupportExpiresAt) {
|
|
5956
|
+
return Promise.resolve(cachedBatchFlushSupport);
|
|
5957
|
+
}
|
|
5958
|
+
invalidateCachedBatchFlushSupport();
|
|
5959
|
+
}
|
|
5960
|
+
if (supportsBatchFlushPromise !== void 0) return supportsBatchFlushPromise;
|
|
5961
|
+
const probe = getJson(
|
|
5962
|
+
target,
|
|
5963
|
+
options.serviceId,
|
|
5964
|
+
"/engram/v1/capabilities",
|
|
5965
|
+
timeoutMs
|
|
5966
|
+
).then((response) => {
|
|
5967
|
+
const isSuccessfulResponse = response.status >= 200 && response.status < 300;
|
|
5968
|
+
if (isSuccessfulResponse && response.body !== null) {
|
|
5969
|
+
const batchFlushSupport = response.body.lcmCompactionFlushBatch;
|
|
5970
|
+
if (typeof batchFlushSupport === "boolean") {
|
|
5971
|
+
cacheBatchFlushSupport(batchFlushSupport);
|
|
5972
|
+
return batchFlushSupport;
|
|
5973
|
+
}
|
|
5974
|
+
return false;
|
|
5975
|
+
}
|
|
5976
|
+
if (response.status === 204 || response.status === 404 || response.status === 405 || response.status === 501) {
|
|
5977
|
+
cacheBatchFlushSupport(false);
|
|
5978
|
+
}
|
|
5979
|
+
return false;
|
|
5980
|
+
}).catch(() => false);
|
|
5981
|
+
supportsBatchFlushPromise = probe.finally(() => {
|
|
5982
|
+
supportsBatchFlushPromise = void 0;
|
|
5983
|
+
});
|
|
5984
|
+
return supportsBatchFlushPromise;
|
|
5985
|
+
};
|
|
5834
5986
|
const flushHandler = async (event, ctx) => {
|
|
5835
|
-
const fromEvent = event?.sessionKey;
|
|
5836
|
-
const sessionKey = typeof fromEvent === "string" && fromEvent.length > 0 ? fromEvent : sessionKeyFrom(event, ctx);
|
|
5837
5987
|
try {
|
|
5838
|
-
|
|
5988
|
+
const deadline = Date.now() + options.flushTimeoutMs;
|
|
5989
|
+
const remainingTimeout = () => Math.max(1, deadline - Date.now());
|
|
5990
|
+
const sessionKey = lifecycleSessionKeyFrom(event, ctx);
|
|
5991
|
+
if (sessionKey === void 0) {
|
|
5992
|
+
log2.warn("delegate flush skipped: lifecycle event has malformed session key");
|
|
5993
|
+
return false;
|
|
5994
|
+
}
|
|
5995
|
+
const namespaces = await lifecycleSessionNamespacesFrom(
|
|
5996
|
+
sessionKey,
|
|
5997
|
+
event,
|
|
5998
|
+
ctx,
|
|
5999
|
+
namespace,
|
|
6000
|
+
namespaceBindings
|
|
6001
|
+
);
|
|
6002
|
+
const flushNamespace = (sessionNamespace) => postJson(
|
|
5839
6003
|
target,
|
|
5840
6004
|
options.serviceId,
|
|
5841
6005
|
"/engram/v1/lcm/compaction/flush",
|
|
5842
|
-
withNamespace(
|
|
5843
|
-
|
|
6006
|
+
withNamespace(sessionNamespace, { sessionKey }),
|
|
6007
|
+
remainingTimeout()
|
|
5844
6008
|
);
|
|
6009
|
+
const flushIndividually = async () => {
|
|
6010
|
+
const outcomes = await Promise.allSettled(namespaces.map(flushNamespace));
|
|
6011
|
+
return outcomes.every(
|
|
6012
|
+
(outcome) => outcome.status === "fulfilled" && outcome.value !== null && outcome.value.flushed === true
|
|
6013
|
+
);
|
|
6014
|
+
};
|
|
6015
|
+
if (namespaces.length <= 1 || await supportsBatchFlush(remainingTimeout())) {
|
|
6016
|
+
if (namespaces.length <= 1) {
|
|
6017
|
+
const response = await flushNamespace(namespaces[0]);
|
|
6018
|
+
return response !== null && response.flushed === true;
|
|
6019
|
+
}
|
|
6020
|
+
try {
|
|
6021
|
+
const response = await postJson(
|
|
6022
|
+
target,
|
|
6023
|
+
options.serviceId,
|
|
6024
|
+
"/engram/v1/lcm/compaction/flush",
|
|
6025
|
+
{
|
|
6026
|
+
sessionKey,
|
|
6027
|
+
namespaces: namespaces.map((sessionNamespace) => sessionNamespace ?? "")
|
|
6028
|
+
},
|
|
6029
|
+
remainingTimeout()
|
|
6030
|
+
);
|
|
6031
|
+
if (response === null) {
|
|
6032
|
+
invalidateCachedBatchFlushSupport();
|
|
6033
|
+
return flushIndividually();
|
|
6034
|
+
}
|
|
6035
|
+
const responseNamespaces = response.namespaces;
|
|
6036
|
+
const responseResults = response.results;
|
|
6037
|
+
const isBatchResponse = Array.isArray(responseNamespaces) && Array.isArray(responseResults) && responseNamespaces.length === namespaces.length && responseNamespaces.every(
|
|
6038
|
+
(responseNamespace, index) => responseNamespace === (namespaces[index] ?? "")
|
|
6039
|
+
) && responseResults.length === namespaces.length;
|
|
6040
|
+
if (!isBatchResponse) {
|
|
6041
|
+
invalidateCachedBatchFlushSupport();
|
|
6042
|
+
return flushIndividually();
|
|
6043
|
+
}
|
|
6044
|
+
if (response.flushed !== true) {
|
|
6045
|
+
invalidateCachedBatchFlushSupport();
|
|
6046
|
+
return false;
|
|
6047
|
+
}
|
|
6048
|
+
return true;
|
|
6049
|
+
} catch {
|
|
6050
|
+
invalidateCachedBatchFlushSupport();
|
|
6051
|
+
return flushIndividually();
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
return flushIndividually();
|
|
5845
6055
|
} catch (err) {
|
|
5846
6056
|
log2.warn(`delegate flush failed: ${String(err)}`);
|
|
6057
|
+
return false;
|
|
5847
6058
|
}
|
|
5848
6059
|
};
|
|
5849
6060
|
api.on("before_compaction", flushHandler);
|
|
5850
6061
|
if (options.flushOnResetEnabled) {
|
|
5851
|
-
|
|
5852
|
-
api.on("
|
|
6062
|
+
const flushEndedSession = async (event, ctx) => flushHandler(event, ctx);
|
|
6063
|
+
api.on("before_reset", flushEndedSession);
|
|
6064
|
+
api.on("session_end", flushEndedSession);
|
|
5853
6065
|
}
|
|
5854
6066
|
log2.info(
|
|
5855
6067
|
`[${options.serviceId}] bridge mode delegate: memory loop backed by daemon at ${target.host}:${target.port} (embedded orchestrator skipped; tools/CLI/surfaces stay daemon-side)`
|
|
@@ -5858,7 +6070,130 @@ function registerDelegateRuntime(api, options) {
|
|
|
5858
6070
|
function activeDelegateAuthorizationOperations(options) {
|
|
5859
6071
|
return options.allowPromptInjection && options.recallBudgetChars !== 0 ? DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS : DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS.slice(1);
|
|
5860
6072
|
}
|
|
6073
|
+
var delegateNamespaceMigrationChains = /* @__PURE__ */ new Map();
|
|
6074
|
+
var queueDelegateNamespaceMigration = (bindingPath, sessionKey, operation) => {
|
|
6075
|
+
let sessionChains = delegateNamespaceMigrationChains.get(bindingPath);
|
|
6076
|
+
if (sessionChains === void 0) {
|
|
6077
|
+
sessionChains = /* @__PURE__ */ new Map();
|
|
6078
|
+
delegateNamespaceMigrationChains.set(bindingPath, sessionChains);
|
|
6079
|
+
}
|
|
6080
|
+
const prior = sessionChains.get(sessionKey) ?? Promise.resolve();
|
|
6081
|
+
const run = prior.catch(() => void 0).then(operation);
|
|
6082
|
+
const settled = run.then(
|
|
6083
|
+
() => void 0,
|
|
6084
|
+
() => void 0
|
|
6085
|
+
);
|
|
6086
|
+
sessionChains.set(sessionKey, settled);
|
|
6087
|
+
void settled.then(() => {
|
|
6088
|
+
if (sessionChains?.get(sessionKey) !== settled) return;
|
|
6089
|
+
sessionChains.delete(sessionKey);
|
|
6090
|
+
if (sessionChains.size === 0 && delegateNamespaceMigrationChains.get(bindingPath) === sessionChains) {
|
|
6091
|
+
delegateNamespaceMigrationChains.delete(bindingPath);
|
|
6092
|
+
}
|
|
6093
|
+
});
|
|
6094
|
+
return run;
|
|
6095
|
+
};
|
|
6096
|
+
function createDelegateNamespaceBindingStore(memoryDir, serviceId, isLegacyAdapterActive) {
|
|
6097
|
+
const bindingPath = (pluginId) => path4.join(memoryDir, "state", "plugins", pluginId, "session-namespace-bindings.json");
|
|
6098
|
+
const primaryPath = bindingPath(serviceId);
|
|
6099
|
+
const primary = createFileSessionNamespaceBindingStore(primaryPath);
|
|
6100
|
+
if (serviceId !== REMNIC_OPENCLAW_PLUGIN_ID) return primary;
|
|
6101
|
+
const legacy = createFileSessionNamespaceBindingStore(
|
|
6102
|
+
bindingPath(REMNIC_OPENCLAW_LEGACY_PLUGIN_ID)
|
|
6103
|
+
);
|
|
6104
|
+
const migratedLegacySessions = /* @__PURE__ */ new Set();
|
|
6105
|
+
const rememberMigratedLegacySession = (sessionKey) => {
|
|
6106
|
+
if (migratedLegacySessions.has(sessionKey)) return;
|
|
6107
|
+
migratedLegacySessions.add(sessionKey);
|
|
6108
|
+
while (migratedLegacySessions.size > SESSION_NAMESPACE_BINDING_MAX_ENTRIES) {
|
|
6109
|
+
const oldest = migratedLegacySessions.values().next().value;
|
|
6110
|
+
if (oldest === void 0) return;
|
|
6111
|
+
migratedLegacySessions.delete(oldest);
|
|
6112
|
+
}
|
|
6113
|
+
};
|
|
6114
|
+
const queueSessionMigration = (sessionKey, operation) => queueDelegateNamespaceMigration(primaryPath, sessionKey, operation);
|
|
6115
|
+
const readLegacyNamespaces = async (sessionKey, current) => {
|
|
6116
|
+
if (!isLegacyAdapterActive() && migratedLegacySessions.has(sessionKey)) return [];
|
|
6117
|
+
try {
|
|
6118
|
+
const previous = await legacy.namespacesFor(sessionKey);
|
|
6119
|
+
if (previous.length === 0) rememberMigratedLegacySession(sessionKey);
|
|
6120
|
+
return previous;
|
|
6121
|
+
} catch (err) {
|
|
6122
|
+
if (current.length > 0) {
|
|
6123
|
+
log2.warn(
|
|
6124
|
+
`[${serviceId}] delegate legacy namespace read failed; using canonical bindings: ${String(err)}`
|
|
6125
|
+
);
|
|
6126
|
+
return [];
|
|
6127
|
+
}
|
|
6128
|
+
throw err;
|
|
6129
|
+
}
|
|
6130
|
+
};
|
|
6131
|
+
const mergeNamespaceHistory = (current, previous) => {
|
|
6132
|
+
const merged = [];
|
|
6133
|
+
for (const remembered of [...previous, ...current]) {
|
|
6134
|
+
const existing = merged.indexOf(remembered);
|
|
6135
|
+
if (existing >= 0) merged.splice(existing, 1);
|
|
6136
|
+
merged.push(remembered);
|
|
6137
|
+
}
|
|
6138
|
+
return merged.slice(-SESSION_NAMESPACE_BINDING_MAX_NAMESPACES);
|
|
6139
|
+
};
|
|
6140
|
+
const persistNamespaceHistory = async (store, sessionKey, namespaces) => {
|
|
6141
|
+
if (store.replace !== void 0) {
|
|
6142
|
+
await store.replace(sessionKey, namespaces);
|
|
6143
|
+
return;
|
|
6144
|
+
}
|
|
6145
|
+
for (const namespace of namespaces) {
|
|
6146
|
+
await store.remember(sessionKey, namespace);
|
|
6147
|
+
}
|
|
6148
|
+
};
|
|
6149
|
+
const completeLegacyMigration = async (sessionKey) => {
|
|
6150
|
+
if (!isLegacyAdapterActive()) {
|
|
6151
|
+
try {
|
|
6152
|
+
await legacy.replace?.(sessionKey, []);
|
|
6153
|
+
} catch (err) {
|
|
6154
|
+
log2.warn(`[${serviceId}] delegate legacy namespace cleanup failed: ${String(err)}`);
|
|
6155
|
+
}
|
|
6156
|
+
}
|
|
6157
|
+
rememberMigratedLegacySession(sessionKey);
|
|
6158
|
+
};
|
|
6159
|
+
return {
|
|
6160
|
+
async namespacesFor(sessionKey) {
|
|
6161
|
+
return queueSessionMigration(sessionKey, async () => {
|
|
6162
|
+
const current = await primary.namespacesFor(sessionKey);
|
|
6163
|
+
const previous = await readLegacyNamespaces(sessionKey, current);
|
|
6164
|
+
if (previous.length === 0) return current;
|
|
6165
|
+
const merged = mergeNamespaceHistory(current, previous);
|
|
6166
|
+
const hasMissingLegacy = previous.some((remembered) => !current.includes(remembered));
|
|
6167
|
+
if (!hasMissingLegacy) {
|
|
6168
|
+
await completeLegacyMigration(sessionKey);
|
|
6169
|
+
return current;
|
|
6170
|
+
}
|
|
6171
|
+
try {
|
|
6172
|
+
await persistNamespaceHistory(primary, sessionKey, merged);
|
|
6173
|
+
await completeLegacyMigration(sessionKey);
|
|
6174
|
+
} catch (err) {
|
|
6175
|
+
log2.warn(`[${serviceId}] delegate namespace migration failed: ${String(err)}`);
|
|
6176
|
+
}
|
|
6177
|
+
return merged;
|
|
6178
|
+
});
|
|
6179
|
+
},
|
|
6180
|
+
async remember(sessionKey, namespace) {
|
|
6181
|
+
return queueSessionMigration(sessionKey, async () => {
|
|
6182
|
+
const current = await primary.namespacesFor(sessionKey);
|
|
6183
|
+
const previous = await readLegacyNamespaces(sessionKey, current);
|
|
6184
|
+
if (previous.length === 0) {
|
|
6185
|
+
await primary.remember(sessionKey, namespace);
|
|
6186
|
+
return;
|
|
6187
|
+
}
|
|
6188
|
+
const merged = mergeNamespaceHistory([...current, namespace], previous);
|
|
6189
|
+
await persistNamespaceHistory(primary, sessionKey, merged);
|
|
6190
|
+
await completeLegacyMigration(sessionKey);
|
|
6191
|
+
});
|
|
6192
|
+
}
|
|
6193
|
+
};
|
|
6194
|
+
}
|
|
5861
6195
|
var delegateHookApiServices = /* @__PURE__ */ new WeakMap();
|
|
6196
|
+
var delegateActiveServiceIds = /* @__PURE__ */ new Set();
|
|
5862
6197
|
var delegateEmbeddedFallbackApis = /* @__PURE__ */ new WeakSet();
|
|
5863
6198
|
var delegateAuthorizationPreflightServices = /* @__PURE__ */ new WeakMap();
|
|
5864
6199
|
function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkDaemonHealthSync }) {
|
|
@@ -5898,6 +6233,7 @@ function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkD
|
|
|
5898
6233
|
(boundServices ?? delegateHookApiServices.set(api, /* @__PURE__ */ new Set()).get(api))?.add(
|
|
5899
6234
|
options.serviceId
|
|
5900
6235
|
);
|
|
6236
|
+
delegateActiveServiceIds.add(options.serviceId);
|
|
5901
6237
|
}
|
|
5902
6238
|
const toggleStore = options.sessionTogglesEnabled ? createFileToggleStore(
|
|
5903
6239
|
path4.join(options.memoryDir, "state", "plugins", options.serviceId, "session-toggles.json"),
|
|
@@ -5914,6 +6250,11 @@ function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkD
|
|
|
5914
6250
|
serviceId: options.serviceId,
|
|
5915
6251
|
target,
|
|
5916
6252
|
namespace: "",
|
|
6253
|
+
namespaceBindings: createDelegateNamespaceBindingStore(
|
|
6254
|
+
options.memoryDir,
|
|
6255
|
+
options.serviceId,
|
|
6256
|
+
() => delegateActiveServiceIds.has(REMNIC_OPENCLAW_LEGACY_PLUGIN_ID)
|
|
6257
|
+
),
|
|
5917
6258
|
allowPromptInjection: options.allowPromptInjection,
|
|
5918
6259
|
passive: options.passive,
|
|
5919
6260
|
gateHeartbeatTurns: options.gateHeartbeatTurns,
|