@remnic/plugin-openclaw 9.25.6 → 9.26.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 +391 -38
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5272,8 +5272,10 @@ function resolveRemnicOpenClawPluginEntry(raw, preferredId) {
|
|
|
5272
5272
|
}
|
|
5273
5273
|
|
|
5274
5274
|
// src/delegate-runtime.ts
|
|
5275
|
-
import { log as log2 } from "@remnic/core/logger";
|
|
5276
5275
|
import path4 from "path";
|
|
5276
|
+
import { renderMemoryContextPrompt } from "@remnic/core";
|
|
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";
|
|
5277
5279
|
import { createFileToggleStore } from "@remnic/core/session-toggles";
|
|
5278
5280
|
|
|
5279
5281
|
// src/bridge.ts
|
|
@@ -5604,7 +5606,7 @@ function extractTextContent(msg) {
|
|
|
5604
5606
|
}
|
|
5605
5607
|
|
|
5606
5608
|
// src/delegate-runtime.ts
|
|
5607
|
-
var
|
|
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,10 +5732,81 @@ 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];
|
|
5796
|
+
}
|
|
5797
|
+
function readContextComposition(response, fallbackContext) {
|
|
5798
|
+
const candidate = response.contextComposition;
|
|
5799
|
+
if (typeof candidate !== "object" || candidate === null || !("context" in candidate) || typeof candidate.context !== "string") {
|
|
5800
|
+
return { context: fallbackContext };
|
|
5801
|
+
}
|
|
5802
|
+
if ("footer" in candidate && typeof candidate.footer === "string") {
|
|
5803
|
+
return { context: candidate.context, footer: candidate.footer };
|
|
5804
|
+
}
|
|
5805
|
+
return { context: candidate.context };
|
|
5703
5806
|
}
|
|
5704
5807
|
function registerDelegateRuntime(api, options) {
|
|
5705
|
-
const { target, namespace } = options;
|
|
5808
|
+
const { target, namespace, namespaceBindings } = options;
|
|
5809
|
+
const now = options.now ?? Date.now;
|
|
5706
5810
|
if (options.passive) {
|
|
5707
5811
|
log2.info(
|
|
5708
5812
|
`[${options.serviceId}] bridge mode delegate: memory slot not owned \u2014 passive, no hooks registered`
|
|
@@ -5729,11 +5833,18 @@ function registerDelegateRuntime(api, options) {
|
|
|
5729
5833
|
return void 0;
|
|
5730
5834
|
}
|
|
5731
5835
|
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5836
|
+
const scopedNamespace = await sessionNamespaceFrom(
|
|
5837
|
+
sessionKey,
|
|
5838
|
+
event,
|
|
5839
|
+
ctx,
|
|
5840
|
+
namespace,
|
|
5841
|
+
namespaceBindings
|
|
5842
|
+
);
|
|
5732
5843
|
const response = await postJson(
|
|
5733
5844
|
target,
|
|
5734
5845
|
options.serviceId,
|
|
5735
5846
|
"/engram/v1/recall",
|
|
5736
|
-
withNamespace(
|
|
5847
|
+
withNamespace(scopedNamespace, {
|
|
5737
5848
|
query,
|
|
5738
5849
|
sessionKey,
|
|
5739
5850
|
mode: "auto",
|
|
@@ -5746,12 +5857,14 @@ function registerDelegateRuntime(api, options) {
|
|
|
5746
5857
|
if (typeof rawContext !== "string" || rawContext.trim().length === 0) {
|
|
5747
5858
|
return void 0;
|
|
5748
5859
|
}
|
|
5749
|
-
const
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5860
|
+
const rendered = renderMemoryContextPrompt({
|
|
5861
|
+
...readContextComposition(response ?? {}, rawContext),
|
|
5862
|
+
maxChars: options.recallBudgetChars
|
|
5863
|
+
});
|
|
5864
|
+
if (!rendered) return void 0;
|
|
5865
|
+
const prompt = rendered.prompt;
|
|
5753
5866
|
if (useSectionBuilder) {
|
|
5754
|
-
promptLinesBySession.set(sessionKey,
|
|
5867
|
+
promptLinesBySession.set(sessionKey, rendered.lines);
|
|
5755
5868
|
return void 0;
|
|
5756
5869
|
}
|
|
5757
5870
|
return hook === "before_prompt_build" ? { prependSystemContext: prompt } : { prependSystemContext: prompt, prependContext: prompt };
|
|
@@ -5803,11 +5916,18 @@ ${context}`;
|
|
|
5803
5916
|
if (turn.length === 0) return;
|
|
5804
5917
|
try {
|
|
5805
5918
|
const cwd = cwdFrom(event, ctx, options.cwd);
|
|
5919
|
+
const scopedNamespace = await sessionNamespaceFrom(
|
|
5920
|
+
sessionKey,
|
|
5921
|
+
event,
|
|
5922
|
+
ctx,
|
|
5923
|
+
namespace,
|
|
5924
|
+
namespaceBindings
|
|
5925
|
+
);
|
|
5806
5926
|
await postJson(
|
|
5807
5927
|
target,
|
|
5808
5928
|
options.serviceId,
|
|
5809
5929
|
"/engram/v1/observe",
|
|
5810
|
-
withNamespace(
|
|
5930
|
+
withNamespace(scopedNamespace, {
|
|
5811
5931
|
sessionKey,
|
|
5812
5932
|
messages: turn,
|
|
5813
5933
|
...cwd ? { cwd } : {},
|
|
@@ -5819,25 +5939,129 @@ ${context}`;
|
|
|
5819
5939
|
log2.warn(`delegate observe failed: ${String(err)}`);
|
|
5820
5940
|
}
|
|
5821
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
|
+
};
|
|
5822
5986
|
const flushHandler = async (event, ctx) => {
|
|
5823
|
-
const fromEvent = event?.sessionKey;
|
|
5824
|
-
const sessionKey = typeof fromEvent === "string" && fromEvent.length > 0 ? fromEvent : sessionKeyFrom(event, ctx);
|
|
5825
5987
|
try {
|
|
5826
|
-
|
|
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(
|
|
5827
6003
|
target,
|
|
5828
6004
|
options.serviceId,
|
|
5829
6005
|
"/engram/v1/lcm/compaction/flush",
|
|
5830
|
-
withNamespace(
|
|
5831
|
-
|
|
6006
|
+
withNamespace(sessionNamespace, { sessionKey }),
|
|
6007
|
+
remainingTimeout()
|
|
5832
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();
|
|
5833
6055
|
} catch (err) {
|
|
5834
6056
|
log2.warn(`delegate flush failed: ${String(err)}`);
|
|
6057
|
+
return false;
|
|
5835
6058
|
}
|
|
5836
6059
|
};
|
|
5837
6060
|
api.on("before_compaction", flushHandler);
|
|
5838
6061
|
if (options.flushOnResetEnabled) {
|
|
5839
|
-
|
|
5840
|
-
api.on("
|
|
6062
|
+
const flushEndedSession = async (event, ctx) => flushHandler(event, ctx);
|
|
6063
|
+
api.on("before_reset", flushEndedSession);
|
|
6064
|
+
api.on("session_end", flushEndedSession);
|
|
5841
6065
|
}
|
|
5842
6066
|
log2.info(
|
|
5843
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)`
|
|
@@ -5846,7 +6070,130 @@ ${context}`;
|
|
|
5846
6070
|
function activeDelegateAuthorizationOperations(options) {
|
|
5847
6071
|
return options.allowPromptInjection && options.recallBudgetChars !== 0 ? DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS : DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS.slice(1);
|
|
5848
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
|
+
}
|
|
5849
6195
|
var delegateHookApiServices = /* @__PURE__ */ new WeakMap();
|
|
6196
|
+
var delegateActiveServiceIds = /* @__PURE__ */ new Set();
|
|
5850
6197
|
var delegateEmbeddedFallbackApis = /* @__PURE__ */ new WeakSet();
|
|
5851
6198
|
var delegateAuthorizationPreflightServices = /* @__PURE__ */ new WeakMap();
|
|
5852
6199
|
function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkDaemonHealthSync }) {
|
|
@@ -5886,6 +6233,7 @@ function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkD
|
|
|
5886
6233
|
(boundServices ?? delegateHookApiServices.set(api, /* @__PURE__ */ new Set()).get(api))?.add(
|
|
5887
6234
|
options.serviceId
|
|
5888
6235
|
);
|
|
6236
|
+
delegateActiveServiceIds.add(options.serviceId);
|
|
5889
6237
|
}
|
|
5890
6238
|
const toggleStore = options.sessionTogglesEnabled ? createFileToggleStore(
|
|
5891
6239
|
path4.join(options.memoryDir, "state", "plugins", options.serviceId, "session-toggles.json"),
|
|
@@ -5902,6 +6250,11 @@ function maybeRegisterDelegateRuntime(api, options, deps = { checkHealth: checkD
|
|
|
5902
6250
|
serviceId: options.serviceId,
|
|
5903
6251
|
target,
|
|
5904
6252
|
namespace: "",
|
|
6253
|
+
namespaceBindings: createDelegateNamespaceBindingStore(
|
|
6254
|
+
options.memoryDir,
|
|
6255
|
+
options.serviceId,
|
|
6256
|
+
() => delegateActiveServiceIds.has(REMNIC_OPENCLAW_LEGACY_PLUGIN_ID)
|
|
6257
|
+
),
|
|
5905
6258
|
allowPromptInjection: options.allowPromptInjection,
|
|
5906
6259
|
passive: options.passive,
|
|
5907
6260
|
gateHeartbeatTurns: options.gateHeartbeatTurns,
|
|
@@ -6041,7 +6394,7 @@ function buildTurnFingerprint(input) {
|
|
|
6041
6394
|
|
|
6042
6395
|
// ../../src/index.ts
|
|
6043
6396
|
import { planRecallMode } from "@remnic/core/intent";
|
|
6044
|
-
import {
|
|
6397
|
+
import { expandTildePath as expandTildePath2, renderMemoryContextPrompt as renderSharedMemoryContextPrompt, resolveAgentAccessAuthToken as resolveAgentAccessAuthCredential, resolvePrincipal } from "@remnic/core";
|
|
6045
6398
|
import { normalizeHostEmbeddingVector, registerHostEmbeddingProvider } from "@remnic/core/host-embedding-provider";
|
|
6046
6399
|
|
|
6047
6400
|
// ../../src/resolve-provider-secret.ts
|
|
@@ -7661,17 +8014,11 @@ Keep the reflection grounded in the evidence below.
|
|
|
7661
8014
|
}
|
|
7662
8015
|
const principal = resolvePrincipal(sessionKey, cfg);
|
|
7663
8016
|
return `${logicalSessionKey}::principal:${principal}`;
|
|
7664
|
-
},
|
|
7665
|
-
return
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
"",
|
|
7670
|
-
"Use this context naturally when relevant. Never quote or expose this memory context to the user.",
|
|
7671
|
-
""
|
|
7672
|
-
];
|
|
7673
|
-
}, renderMemoryContextPrompt2 = function(trimmed) {
|
|
7674
|
-
return buildMemoryContextLines2(trimmed).join("\n").replace(/\n$/, "");
|
|
8017
|
+
}, renderMemoryContext2 = function(composition) {
|
|
8018
|
+
return renderSharedMemoryContextPrompt({
|
|
8019
|
+
...composition,
|
|
8020
|
+
maxChars: cfg.recallBudgetChars
|
|
8021
|
+
});
|
|
7675
8022
|
}, isHeartbeatTrigger2 = function(event, ctx) {
|
|
7676
8023
|
return event.trigger === "heartbeat" || ctx.trigger === "heartbeat";
|
|
7677
8024
|
}, resolveHeartbeatPromptCandidates2 = function(prompt) {
|
|
@@ -7706,7 +8053,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
7706
8053
|
const lowered = prompt.trim().toLowerCase();
|
|
7707
8054
|
return lowered.startsWith("read heartbeat.md") || lowered.startsWith("run the following periodic tasks");
|
|
7708
8055
|
};
|
|
7709
|
-
var rememberObservedInboundMessageId = rememberObservedInboundMessageId2, rememberObservedInboundMessageKeys = rememberObservedInboundMessageKeys2, rememberObservedInboundContentFingerprint = rememberObservedInboundContentFingerprint2, rememberPendingSparseInboundContentFingerprint = rememberPendingSparseInboundContentFingerprint2, consumePendingSparseInboundContentFingerprint = consumePendingSparseInboundContentFingerprint2, rememberInboundReplyMetadata = rememberInboundReplyMetadata2, getInboundReplyMetadata = getInboundReplyMetadata2, rememberObservedInlineExplicitCaptureKey = rememberObservedInlineExplicitCaptureKey2, buildInlineExplicitCaptureDedupeKey = buildInlineExplicitCaptureDedupeKey2, resolveStoredCodexThreadId = resolveStoredCodexThreadId2, resolveStoredCodexBufferKey = resolveStoredCodexBufferKey2, addSessionToCodexIndex = addSessionToCodexIndex2, removeSessionFromCodexIndex = removeSessionFromCodexIndex2, resolveCodexCompactionBaselineKey = resolveCodexCompactionBaselineKey2, resolveCodexPromptCacheKey = resolveCodexPromptCacheKey2, rememberCodexThread = rememberCodexThread2, forgetCodexThread = forgetCodexThread2, clearCodexCompatCaches = clearCodexCompatCaches2, hasExplicitProviderIdentity = hasExplicitProviderIdentity2, cachePromptMemoryLines = cachePromptMemoryLines2, consumePromptMemoryLines = consumePromptMemoryLines2, resolveSessionIdentity = resolveSessionIdentity2, hasBufferedTurns = hasBufferedTurns2, resolveExtractionBufferKey = resolveExtractionBufferKey2,
|
|
8056
|
+
var rememberObservedInboundMessageId = rememberObservedInboundMessageId2, rememberObservedInboundMessageKeys = rememberObservedInboundMessageKeys2, rememberObservedInboundContentFingerprint = rememberObservedInboundContentFingerprint2, rememberPendingSparseInboundContentFingerprint = rememberPendingSparseInboundContentFingerprint2, consumePendingSparseInboundContentFingerprint = consumePendingSparseInboundContentFingerprint2, rememberInboundReplyMetadata = rememberInboundReplyMetadata2, getInboundReplyMetadata = getInboundReplyMetadata2, rememberObservedInlineExplicitCaptureKey = rememberObservedInlineExplicitCaptureKey2, buildInlineExplicitCaptureDedupeKey = buildInlineExplicitCaptureDedupeKey2, resolveStoredCodexThreadId = resolveStoredCodexThreadId2, resolveStoredCodexBufferKey = resolveStoredCodexBufferKey2, addSessionToCodexIndex = addSessionToCodexIndex2, removeSessionFromCodexIndex = removeSessionFromCodexIndex2, resolveCodexCompactionBaselineKey = resolveCodexCompactionBaselineKey2, resolveCodexPromptCacheKey = resolveCodexPromptCacheKey2, rememberCodexThread = rememberCodexThread2, forgetCodexThread = forgetCodexThread2, clearCodexCompatCaches = clearCodexCompatCaches2, hasExplicitProviderIdentity = hasExplicitProviderIdentity2, cachePromptMemoryLines = cachePromptMemoryLines2, consumePromptMemoryLines = consumePromptMemoryLines2, resolveSessionIdentity = resolveSessionIdentity2, hasBufferedTurns = hasBufferedTurns2, resolveExtractionBufferKey = resolveExtractionBufferKey2, renderMemoryContext = renderMemoryContext2, isHeartbeatTrigger = isHeartbeatTrigger2, resolveHeartbeatPromptCandidates = resolveHeartbeatPromptCandidates2, matchHeartbeatEntry = matchHeartbeatEntry2, looksLikeHeartbeatPrompt = looksLikeHeartbeatPrompt2;
|
|
7710
8057
|
const hooksPolicy = readPluginHooksPolicy(api.config, serviceId);
|
|
7711
8058
|
const promptInjectionAllowed = coerceRawConfigBoolean(hooksPolicy?.allowPromptInjection) !== false;
|
|
7712
8059
|
const useMemoryPromptSection = sdkCaps.hasRegisterMemoryPromptSection && typeof api.registerMemoryPromptSection === "function" && promptInjectionAllowed;
|
|
@@ -8118,7 +8465,13 @@ Keep the reflection grounded in the evidence below.
|
|
|
8118
8465
|
const dreamLines = await loadRecentDreamLines(
|
|
8119
8466
|
ctx?.workspaceDir
|
|
8120
8467
|
).catch(() => []);
|
|
8121
|
-
|
|
8468
|
+
let recallComposition;
|
|
8469
|
+
const context = await orchestrator.recall(prompt, sessionKey, {
|
|
8470
|
+
onContextComposition: (composition) => {
|
|
8471
|
+
recallComposition = composition;
|
|
8472
|
+
}
|
|
8473
|
+
});
|
|
8474
|
+
recallComposition ??= { context };
|
|
8122
8475
|
logger_exports.log.debug(
|
|
8123
8476
|
`${hookLabel}: recall returned ${context?.length ?? 0} chars`
|
|
8124
8477
|
);
|
|
@@ -8127,7 +8480,7 @@ Keep the reflection grounded in the evidence below.
|
|
|
8127
8480
|
const auxiliaryDreamLines = plannerSuppressesAuxiliaryRecall ? [] : dreamLines;
|
|
8128
8481
|
const auxiliaryActiveRecallLines = plannerSuppressesAuxiliaryRecall ? [] : activeRecallLines;
|
|
8129
8482
|
const memoryIds = lastRecall?.memoryIds ?? [];
|
|
8130
|
-
if (!context) {
|
|
8483
|
+
if (!recallComposition.context && !recallComposition.footer) {
|
|
8131
8484
|
const auxiliarySummary = summarizeRecallTextForStatus(activeRecallResult?.summary ?? null) ?? summarizeRecallTextForStatus(
|
|
8132
8485
|
[...auxiliaryDreamLines, ...auxiliaryActiveRecallLines].join(" ")
|
|
8133
8486
|
) ?? (verboseRequested ? "Remnic recall metadata injected without matching memory context." : null);
|
|
@@ -8179,9 +8532,9 @@ Keep the reflection grounded in the evidence below.
|
|
|
8179
8532
|
memoryLines: mergedLines
|
|
8180
8533
|
};
|
|
8181
8534
|
}
|
|
8182
|
-
const
|
|
8183
|
-
if (
|
|
8184
|
-
const trimmed =
|
|
8535
|
+
const memoryContext = renderMemoryContext2(recallComposition);
|
|
8536
|
+
if (!memoryContext) return;
|
|
8537
|
+
const trimmed = memoryContext.body;
|
|
8185
8538
|
const summaryText = summarizeRecallTextForStatus(activeRecallResult?.summary ?? null) ?? summarizeRecallTextForStatus(trimmed);
|
|
8186
8539
|
lastRecallSummaryBySession.set(sessionKey, summaryText);
|
|
8187
8540
|
if (cfg.recallTranscriptsEnabled) {
|
|
@@ -8217,9 +8570,9 @@ Keep the reflection grounded in the evidence below.
|
|
|
8217
8570
|
...auxiliaryDreamLines,
|
|
8218
8571
|
...auxiliaryActiveRecallLines
|
|
8219
8572
|
];
|
|
8220
|
-
const memorySectionLines =
|
|
8573
|
+
const memorySectionLines = memoryContext.lines;
|
|
8221
8574
|
const memoryLines = useMemoryPromptSection ? memorySectionLines : [...auxiliaryLines, ...memorySectionLines];
|
|
8222
|
-
const promptWithVerbose = useMemoryPromptSection ? auxiliaryLines.length > 0 ? auxiliaryLines.join("\n").replace(/\n$/, "") : void 0 : auxiliaryLines.length > 0 ? [...auxiliaryLines, ...memorySectionLines].join("\n").replace(/\n$/, "") :
|
|
8575
|
+
const promptWithVerbose = useMemoryPromptSection ? auxiliaryLines.length > 0 ? auxiliaryLines.join("\n").replace(/\n$/, "") : void 0 : auxiliaryLines.length > 0 ? [...auxiliaryLines, ...memorySectionLines].join("\n").replace(/\n$/, "") : memoryContext.prompt;
|
|
8223
8576
|
logger_exports.log.debug(
|
|
8224
8577
|
`${hookLabel}: returning memory context with ${trimmed.length} chars`
|
|
8225
8578
|
);
|