@remnic/plugin-openclaw 9.3.563 → 9.3.564

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/README.md CHANGED
@@ -49,7 +49,7 @@ The package metadata keeps the installer compatibility floor at the single
49
49
  `>=2026.4.1` shape OpenClaw setup expects because that older floor is still
50
50
  more permissive than the active 60-day requirement. The peer and plugin-API
51
51
  compatibility ranges explicitly include reviewed prerelease hosts in that
52
- window. The adapter separately records `2026.6.2-alpha.1` as the latest
52
+ window. The adapter separately records `2026.6.2-alpha.2` as the latest
53
53
  reviewed OpenClaw source-tag target.
54
54
 
55
55
  When adding newer OpenClaw manifest surfaces, keep older-compatible metadata in
@@ -192,11 +192,11 @@ for the Remnic adapter surfaces. The May 31 sweep checked source tags
192
192
  #1203 through #1245, excluding unrelated issue #1211. The June 2 sweep reviewed
193
193
  Remnic issues #1258, #1259, #1266, and #1271 against OpenClaw tags
194
194
  `v2026.5.31-beta.4`, `v2026.6.1-alpha.1`, `v2026.6.1-alpha.2`,
195
- `v2026.6.1-alpha.3`, `v2026.6.1-beta.1`, `v2026.6.1-beta.2`, and
196
- `v2026.6.2-alpha.1`. The existing SDK snapshot still matched (`14 registrars,
197
- 22 hooks, 2 manifest contracts`) for each tag. `v2026.6.2-alpha.1` exists as an
198
- upstream source tag, but as of June 2, 2026 it is not a GitHub release page or
199
- published npm package.
195
+ `v2026.6.1-alpha.3`, `v2026.6.1-beta.1`, `v2026.6.1-beta.2`,
196
+ `v2026.6.2-alpha.1`, and `v2026.6.2-alpha.2`. The existing SDK snapshot still
197
+ matched (`14 registrars, 22 hooks, 2 manifest contracts`) for each tag.
198
+ `v2026.6.2-alpha.1` and `v2026.6.2-alpha.2` exist as upstream source tags, but
199
+ as of June 2, 2026 they are not GitHub release pages or published npm packages.
200
200
 
201
201
  OpenClaw 2026.5.16 package-entry discovery prefers explicit built runtime
202
202
  entries for installed packages. The published Remnic adapter declares
@@ -236,15 +236,31 @@ because the adapter owns mixed memory-slot hooks, lifecycle handlers, slash
236
236
  command metadata, public artifacts, and runtime tools rather than only static
237
237
  tools.
238
238
 
239
- OpenClaw 2026.5.20-beta.2 through the reviewed `2026.6.2-alpha.1` source tag
239
+ OpenClaw 2026.5.20-beta.2 through the reviewed `2026.6.2-alpha.2` source tag
240
240
  keep the Remnic-required plugin install, ClawHub fallback, manifest contract,
241
241
  hook, memory-slot, gateway LLM, and plugin security-scan surfaces compatible.
242
242
  OpenClaw 2026.5.31-beta.4 added optional `plugin-sdk/chat-channel-ids` and
243
243
  `plugin-sdk/memory-core-host-embedding-registry` subpaths, and
244
- `2026.6.2-alpha.1` adds quoted-reply metadata fields to inbound and
245
- `before_dispatch` hook contexts. Remnic does not consume those optional
246
- surfaces in the memory adapter, so no runtime adapter code change is required.
247
- The package metadata now records `2026.6.2-alpha.1` as the reviewed OpenClaw
244
+ `2026.6.2-alpha.1`/`2026.6.2-alpha.2` add quoted-reply metadata fields to
245
+ inbound and `before_dispatch` hook contexts. Remnic consumes those optional
246
+ surfaces only through compatibility gates:
247
+
248
+ - `hostEmbeddingProviderEnabled` (default `true`) lets Remnic prefer
249
+ OpenClaw memory/generic embedding providers for semantic fallback and
250
+ embedded vector backends when the host SDK exposes them. Provider creation
251
+ failures fall back to Remnic's existing embedding path.
252
+ - `openclawMessageReceivedCaptureEnabled` (default `true`) captures inbound
253
+ `message_received` content into transcripts when the host emits that hook.
254
+ - `openclawReplyMetadataCaptureEnabled` (default `true`) stores bounded
255
+ `messageId`, `threadId`, `replyToId`, `replyToBody`, and `replyToSender`
256
+ transcript metadata.
257
+ - `openclawReplyMetadataExtractionHintsEnabled` (default `false`) prepends
258
+ bounded quoted-reply context to user turns before extraction.
259
+ - `openclawChannelEnvelopeCleaningEnabled` (default `true`) uses OpenClaw's
260
+ canonical channel envelope prefixes when the SDK subpath exists, with the
261
+ legacy OpenClaw-only cleaner preserved for older hosts.
262
+
263
+ The package metadata now records `2026.6.2-alpha.2` as the reviewed OpenClaw
248
264
  source-tag target and keeps the stable `>=2026.4.1` installer floor plus
249
265
  reviewed prerelease peer/plugin-API hosts eligible.
250
266
 
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ import * as day_summary_star from "@remnic/core/day-summary";
24
24
  // ../../src/index.ts
25
25
  import OpenAI from "openai";
26
26
  import { createRequire } from "module";
27
+ import { createHash as createHash2 } from "crypto";
27
28
 
28
29
  // ../../src/config.ts
29
30
  var config_exports = {};
@@ -2943,13 +2944,23 @@ import { readEnvVar, resolveHomeDir } from "@remnic/core/runtime/env";
2943
2944
  import { migrateFromEngram, rollbackFromEngramMigration } from "@remnic/core/migrate/from-engram";
2944
2945
 
2945
2946
  // ../../src/user-message-cleaning.ts
2946
- function cleanUserMessage(content) {
2947
+ var DEFAULT_CHANNEL_ENVELOPE_PREFIXES = ["OpenClaw"];
2948
+ function createOpenClawUserMessageCleaner(prefixes, options = {}) {
2949
+ const normalized = normalizeOpenClawChannelEnvelopePrefixes(prefixes);
2950
+ const includeLegacyChannelEnvelopePattern = options.includeLegacyChannelEnvelopePattern ?? true;
2951
+ const platformHeaderPattern = channelEnvelopeHeaderPattern(
2952
+ normalized,
2953
+ includeLegacyChannelEnvelopePattern === true
2954
+ );
2955
+ return (content) => cleanUserMessageWithPattern(content, platformHeaderPattern);
2956
+ }
2957
+ function cleanUserMessageWithPattern(content, platformHeaderPattern) {
2947
2958
  let cleaned = content;
2948
2959
  cleaned = cleaned.replace(
2949
2960
  /<supermemory-context[^>]*>[\s\S]*?<\/supermemory-context>\s*/gi,
2950
2961
  ""
2951
2962
  );
2952
- const platformHeader = cleaned.match(/^\[\w+\s+.+?\s+id:\d+\s+[^\]]+\]\s*/);
2963
+ const platformHeader = cleaned.match(platformHeaderPattern);
2953
2964
  const hasPlatformHeader = platformHeader !== null;
2954
2965
  if (platformHeader) {
2955
2966
  cleaned = cleaned.slice(platformHeader[0].length);
@@ -2963,6 +2974,21 @@ function cleanUserMessage(content) {
2963
2974
  }
2964
2975
  return cleaned.trim();
2965
2976
  }
2977
+ function normalizeOpenClawChannelEnvelopePrefixes(prefixes) {
2978
+ const cleaned = prefixes.map((prefix) => typeof prefix === "string" ? prefix.trim() : "").filter((prefix) => prefix.length > 0);
2979
+ return cleaned.length > 0 ? cleaned : [...DEFAULT_CHANNEL_ENVELOPE_PREFIXES];
2980
+ }
2981
+ function channelEnvelopeHeaderPattern(prefixes, includeLegacyChannelEnvelopePattern) {
2982
+ const alternatives = prefixes.map(escapeRegExp).join("|");
2983
+ const patterns = [`\\[(?:${alternatives})\\s+.+?\\s+id:\\d+\\s+[^\\]]+\\]`];
2984
+ if (includeLegacyChannelEnvelopePattern) {
2985
+ patterns.push("\\[\\w+\\s+.+?\\s+id:\\d+\\s+[^\\]]+\\]");
2986
+ }
2987
+ return new RegExp(`^(?:${patterns.join("|")})\\s*`);
2988
+ }
2989
+ function escapeRegExp(value) {
2990
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2991
+ }
2966
2992
 
2967
2993
  // src/public-artifacts.ts
2968
2994
  import { readdir, access, stat, lstat, realpath } from "fs/promises";
@@ -3484,7 +3510,7 @@ async function syncHeartbeatSurfaceEntries(params) {
3484
3510
  }
3485
3511
  return { created, updated, linked: 0 };
3486
3512
  }
3487
- function escapeRegExp(value) {
3513
+ function escapeRegExp2(value) {
3488
3514
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3489
3515
  }
3490
3516
  function buildDelimitedBoundaryClass() {
@@ -3495,7 +3521,7 @@ function compileDelimitedPhrasePattern(value) {
3495
3521
  if (normalized.length === 0) return null;
3496
3522
  const boundaryClass = buildDelimitedBoundaryClass();
3497
3523
  return new RegExp(
3498
- `(^|[^${boundaryClass}])${escapeRegExp(normalized)}([^${boundaryClass}]|$)`
3524
+ `(^|[^${boundaryClass}])${escapeRegExp2(normalized)}([^${boundaryClass}]|$)`
3499
3525
  );
3500
3526
  }
3501
3527
  function matchesDelimitedPattern(haystack, pattern) {
@@ -4074,6 +4100,7 @@ function buildTurnFingerprint(input) {
4074
4100
  // ../../src/index.ts
4075
4101
  import { planRecallMode } from "@remnic/core/intent";
4076
4102
  import { resolvePrincipal, resolveAgentAccessAuthToken as resolveAgentAccessAuthCredential, expandTildePath } from "@remnic/core";
4103
+ import { normalizeHostEmbeddingVector, registerHostEmbeddingProvider } from "@remnic/core/host-embedding-provider";
4077
4104
 
4078
4105
  // ../../src/resolve-provider-secret.ts
4079
4106
  var resolve_provider_secret_exports = {};
@@ -4372,6 +4399,8 @@ function buildServiceKeys(serviceId) {
4372
4399
  const suffix = `::${serviceId}`;
4373
4400
  return {
4374
4401
  REGISTERED_GUARD: `__openclawEngramRegistered${suffix}`,
4402
+ HOST_EMBEDDING_UNREGISTER: `__openclawEngramHostEmbeddingUnregister${suffix}`,
4403
+ HOST_EMBEDDING_SIGNATURE: `__openclawEngramHostEmbeddingSignature${suffix}`,
4375
4404
  HOOK_APIS: `__openclawEngramHookApis${suffix}`,
4376
4405
  ACCESS_SERVICE: `__openclawEngramAccessService${suffix}`,
4377
4406
  ACCESS_HTTP_SERVER: `__openclawEngramAccessHttpServer${suffix}`,
@@ -4570,6 +4599,211 @@ function tryDefinePluginEntry(def) {
4570
4599
  return def;
4571
4600
  }
4572
4601
  }
4602
+ var MAX_OBSERVED_INBOUND_MESSAGE_IDS = 1024;
4603
+ var MAX_OBSERVED_INLINE_EXPLICIT_CAPTURE_KEYS = 1024;
4604
+ function requireOpenClawSdkSubpath(subpath) {
4605
+ try {
4606
+ const _require = createRequire(import.meta.url);
4607
+ return _require(subpath);
4608
+ } catch {
4609
+ return null;
4610
+ }
4611
+ }
4612
+ function resolveChannelEnvelopePrefixes(cfg) {
4613
+ if (!cfg.openclawChannelEnvelopeCleaningEnabled) {
4614
+ return { prefixes: ["OpenClaw"], includeLegacyChannelEnvelopePattern: true };
4615
+ }
4616
+ const sdk = requireOpenClawSdkSubpath("openclaw/plugin-sdk/chat-channel-ids");
4617
+ const prefixes = sdk?.BUNDLED_CHAT_CHANNEL_ENVELOPE_PREFIXES;
4618
+ if (!Array.isArray(prefixes)) {
4619
+ return { prefixes: ["OpenClaw"], includeLegacyChannelEnvelopePattern: true };
4620
+ }
4621
+ const cleaned = prefixes.filter((value) => typeof value === "string");
4622
+ return {
4623
+ prefixes: cleaned.length > 0 ? cleaned : ["OpenClaw"],
4624
+ includeLegacyChannelEnvelopePattern: false
4625
+ };
4626
+ }
4627
+ function registerOpenClawHostEmbeddingProvider(params) {
4628
+ const { api, cfg, serviceId } = params;
4629
+ if (cfg.hostEmbeddingProviderEnabled === false) return null;
4630
+ const selected = selectOpenClawEmbeddingAdapter(api, cfg.hostEmbeddingProviderId);
4631
+ if (!selected) return null;
4632
+ const model = cfg.hostEmbeddingProviderModel || selected.adapter.defaultModel || "text-embedding-3-small";
4633
+ const workspaceDir = getOpenClawRuntimeWorkspaceDir(api);
4634
+ let providerPromise = null;
4635
+ let providerInstance = null;
4636
+ const resolveProvider = async () => {
4637
+ if (providerInstance) return providerInstance;
4638
+ providerPromise ??= selected.adapter.create({
4639
+ config: api.config ?? {},
4640
+ workspaceDir,
4641
+ agentDir: workspaceDir,
4642
+ provider: cfg.hostEmbeddingProviderId || selected.adapter.id,
4643
+ model
4644
+ }).then((result) => {
4645
+ providerInstance = result && typeof result === "object" ? result.provider ?? null : null;
4646
+ if (!providerInstance) {
4647
+ logger_exports.log.debug(
4648
+ `OpenClaw host embedding provider ${selected.adapter.id} did not create a provider; using Remnic fallback embeddings`
4649
+ );
4650
+ }
4651
+ return providerInstance;
4652
+ }).catch((error) => {
4653
+ logger_exports.log.debug(
4654
+ `OpenClaw host embedding provider ${selected.adapter.id} unavailable: ${error}`
4655
+ );
4656
+ return null;
4657
+ }).finally(() => {
4658
+ if (!providerInstance) {
4659
+ providerPromise = null;
4660
+ }
4661
+ });
4662
+ return providerPromise;
4663
+ };
4664
+ const hostProvider = {
4665
+ id: `openclaw:${selected.kind}:${selected.adapter.id}`,
4666
+ model: `${selected.kind}:${selected.adapter.id}/${model}`,
4667
+ async embed(text, options) {
4668
+ const provider = await resolveProvider();
4669
+ if (!provider) return null;
4670
+ return embedWithOpenClawProvider(selected.kind, provider, text, options);
4671
+ },
4672
+ async embedBatch(texts, options) {
4673
+ const provider = await resolveProvider();
4674
+ if (!provider) return texts.map(() => null);
4675
+ return embedBatchWithOpenClawProvider(selected.kind, provider, texts, options);
4676
+ },
4677
+ async close() {
4678
+ const close = providerInstance && typeof providerInstance === "object" ? providerInstance.close : void 0;
4679
+ if (typeof close === "function") {
4680
+ await close.call(providerInstance);
4681
+ }
4682
+ }
4683
+ };
4684
+ const unregister = registerHostEmbeddingProvider(cfg.memoryDir, hostProvider);
4685
+ logger_exports.log.info(
4686
+ `registered OpenClaw host embedding provider bridge (${selected.adapter.id}) for ${serviceId}`
4687
+ );
4688
+ return unregister;
4689
+ }
4690
+ function getOpenClawRuntimeWorkspaceDir(api) {
4691
+ const runtimeWorkspaceDir = api.runtime?.agent?.workspaceDir;
4692
+ return typeof runtimeWorkspaceDir === "string" && runtimeWorkspaceDir.length > 0 ? runtimeWorkspaceDir : void 0;
4693
+ }
4694
+ function stableOpenClawConfigSignature(value, seen = /* @__PURE__ */ new WeakSet()) {
4695
+ if (value === null) return "null";
4696
+ const valueType = typeof value;
4697
+ if (valueType === "string" || valueType === "number" || valueType === "boolean") {
4698
+ return JSON.stringify(value);
4699
+ }
4700
+ if (valueType === "bigint") return JSON.stringify(String(value));
4701
+ if (valueType === "undefined" || valueType === "function" || valueType === "symbol") {
4702
+ return JSON.stringify(`[${valueType}]`);
4703
+ }
4704
+ if (Array.isArray(value)) {
4705
+ return `[${value.map((entry) => stableOpenClawConfigSignature(entry, seen)).join(",")}]`;
4706
+ }
4707
+ if (value && valueType === "object") {
4708
+ if (seen.has(value)) return JSON.stringify("[Circular]");
4709
+ seen.add(value);
4710
+ const entries = Object.keys(value).sort().map(
4711
+ (key) => `${JSON.stringify(key)}:${stableOpenClawConfigSignature(
4712
+ value[key],
4713
+ seen
4714
+ )}`
4715
+ );
4716
+ seen.delete(value);
4717
+ return `{${entries.join(",")}}`;
4718
+ }
4719
+ return JSON.stringify(String(value));
4720
+ }
4721
+ function openClawHostEmbeddingConfigSignature(cfg, apiConfig, workspaceDir) {
4722
+ return `sha256:${createHash2("sha256").update(JSON.stringify({
4723
+ enabled: cfg.hostEmbeddingProviderEnabled !== false,
4724
+ memoryDir: cfg.memoryDir,
4725
+ providerId: cfg.hostEmbeddingProviderId ?? "",
4726
+ providerModel: cfg.hostEmbeddingProviderModel ?? "",
4727
+ workspaceDir: workspaceDir ?? "",
4728
+ openClawConfig: stableOpenClawConfigSignature(apiConfig)
4729
+ })).digest("hex")}`;
4730
+ }
4731
+ function selectOpenClawEmbeddingAdapter(api, requestedId) {
4732
+ const memorySdk = loadOpenClawMemoryEmbeddingSdk();
4733
+ const memoryAdapters = memorySdk?.listMemoryEmbeddingProviders?.(api.config) ?? [];
4734
+ const selectedMemory = selectAdapter(memoryAdapters, requestedId);
4735
+ if (selectedMemory) {
4736
+ return { kind: "memory", adapter: selectedMemory };
4737
+ }
4738
+ const genericSdk = requireOpenClawSdkSubpath("openclaw/plugin-sdk/embedding-providers");
4739
+ const genericAdapters = genericSdk?.listEmbeddingProviders?.(api.config) ?? [];
4740
+ const selectedGeneric = selectAdapter(genericAdapters, requestedId);
4741
+ if (selectedGeneric) {
4742
+ return { kind: "generic", adapter: selectedGeneric };
4743
+ }
4744
+ return null;
4745
+ }
4746
+ function loadOpenClawMemoryEmbeddingSdk() {
4747
+ return selectOpenClawMemoryEmbeddingSdk(
4748
+ requireOpenClawSdkSubpath("openclaw/plugin-sdk/memory-core-host-engine-embeddings"),
4749
+ requireOpenClawSdkSubpath("openclaw/plugin-sdk/memory-core-host-embedding-registry")
4750
+ );
4751
+ }
4752
+ function selectOpenClawMemoryEmbeddingSdk(currentSdk, legacySdk) {
4753
+ return currentSdk ?? legacySdk;
4754
+ }
4755
+ function selectAdapter(adapters, requestedId) {
4756
+ const valid = adapters.filter(isOpenClawEmbeddingAdapter);
4757
+ if (valid.length === 0) return null;
4758
+ if (requestedId) {
4759
+ return valid.find((adapter) => adapter.id === requestedId) ?? null;
4760
+ }
4761
+ return valid[0] ?? null;
4762
+ }
4763
+ function isOpenClawEmbeddingAdapter(value) {
4764
+ return Boolean(value) && typeof value === "object" && typeof value.id === "string" && typeof value.create === "function";
4765
+ }
4766
+ async function embedWithOpenClawProvider(_kind, provider, text, options) {
4767
+ if (!provider || typeof provider !== "object") return null;
4768
+ const record = provider;
4769
+ if (options?.inputType === "query" && typeof record.embedQuery === "function") {
4770
+ return normalizeHostEmbeddingVector(
4771
+ await record.embedQuery.call(provider, text, { signal: options.signal })
4772
+ );
4773
+ }
4774
+ if (typeof record.embed === "function") {
4775
+ return normalizeHostEmbeddingVector(
4776
+ await record.embed.call(provider, text, {
4777
+ signal: options?.signal,
4778
+ inputType: options?.inputType
4779
+ })
4780
+ );
4781
+ }
4782
+ if (typeof record.embedBatch === "function") {
4783
+ const vectors = await record.embedBatch.call(provider, [text], {
4784
+ signal: options?.signal,
4785
+ inputType: options?.inputType
4786
+ });
4787
+ return normalizeHostEmbeddingVector(Array.isArray(vectors) ? vectors[0] : null);
4788
+ }
4789
+ return null;
4790
+ }
4791
+ async function embedBatchWithOpenClawProvider(kind, provider, texts, options) {
4792
+ if (!provider || typeof provider !== "object") return texts.map(() => null);
4793
+ const record = provider;
4794
+ if (typeof record.embedBatch === "function") {
4795
+ const vectors = await record.embedBatch.call(provider, texts, {
4796
+ signal: options?.signal,
4797
+ inputType: options?.inputType
4798
+ });
4799
+ return texts.map(
4800
+ (_, index) => normalizeHostEmbeddingVector(Array.isArray(vectors) ? vectors[index] : null)
4801
+ );
4802
+ }
4803
+ return Promise.all(
4804
+ texts.map((text) => embedWithOpenClawProvider(kind, provider, text, options))
4805
+ );
4806
+ }
4573
4807
  var sdkCaps;
4574
4808
  var NON_RUNTIME_REGISTRATION_MODES = /* @__PURE__ */ new Set([
4575
4809
  "discovery",
@@ -4644,10 +4878,47 @@ var pluginDefinition = {
4644
4878
  `[remnic] memory slot not assigned to ${serviceId}; running passively`
4645
4879
  );
4646
4880
  }
4881
+ const channelEnvelopeCleaning = resolveChannelEnvelopePrefixes(cfg);
4882
+ const cleanOpenClawUserMessage = createOpenClawUserMessageCleaner(
4883
+ channelEnvelopeCleaning.prefixes,
4884
+ {
4885
+ includeLegacyChannelEnvelopePattern: channelEnvelopeCleaning.includeLegacyChannelEnvelopePattern
4886
+ }
4887
+ );
4647
4888
  const existing = globalThis[keys.ORCHESTRATOR];
4648
4889
  const orchestrator = existing?.recall ? existing : new Orchestrator(cfg);
4649
4890
  const isFirstRegistration = !globalThis[keys.REGISTERED_GUARD];
4650
4891
  globalThis[keys.REGISTERED_GUARD] = true;
4892
+ const unregisterExistingHostEmbeddingProvider = () => {
4893
+ const unregisterHostEmbedding = globalThis[keys.HOST_EMBEDDING_UNREGISTER];
4894
+ unregisterHostEmbedding?.();
4895
+ delete globalThis[keys.HOST_EMBEDDING_UNREGISTER];
4896
+ delete globalThis[keys.HOST_EMBEDDING_SIGNATURE];
4897
+ };
4898
+ if (passiveMode) {
4899
+ unregisterExistingHostEmbeddingProvider();
4900
+ } else {
4901
+ const hostEmbeddingSignature = openClawHostEmbeddingConfigSignature(
4902
+ cfg,
4903
+ api.config,
4904
+ getOpenClawRuntimeWorkspaceDir(api)
4905
+ );
4906
+ const existingHostEmbeddingSignature = globalThis[keys.HOST_EMBEDDING_SIGNATURE];
4907
+ if (globalThis[keys.HOST_EMBEDDING_UNREGISTER] && existingHostEmbeddingSignature !== hostEmbeddingSignature) {
4908
+ unregisterExistingHostEmbeddingProvider();
4909
+ }
4910
+ if (!globalThis[keys.HOST_EMBEDDING_UNREGISTER]) {
4911
+ const unregisterHostEmbedding = registerOpenClawHostEmbeddingProvider({
4912
+ api,
4913
+ cfg,
4914
+ serviceId
4915
+ });
4916
+ if (unregisterHostEmbedding) {
4917
+ globalThis[keys.HOST_EMBEDDING_UNREGISTER] = unregisterHostEmbedding;
4918
+ globalThis[keys.HOST_EMBEDDING_SIGNATURE] = hostEmbeddingSignature;
4919
+ }
4920
+ }
4921
+ }
4651
4922
  const hookApis = globalThis[keys.HOOK_APIS] ??= /* @__PURE__ */ new WeakSet();
4652
4923
  if (hookApis.has(api)) {
4653
4924
  logger_exports.log.debug(
@@ -4884,7 +5155,83 @@ Keep the reflection grounded in the evidence below.
4884
5155
  }
4885
5156
  );
4886
5157
  if (!passiveMode) {
4887
- let resolveStoredCodexThreadId2 = function(sessionKey) {
5158
+ let rememberObservedInboundMessageId2 = function(messageKey) {
5159
+ if (!observedInboundMessageIds.has(messageKey)) {
5160
+ observedInboundMessageIds.add(messageKey);
5161
+ observedInboundMessageIdOrder.push(messageKey);
5162
+ }
5163
+ while (observedInboundMessageIdOrder.length > MAX_OBSERVED_INBOUND_MESSAGE_IDS) {
5164
+ const expired = observedInboundMessageIdOrder.shift();
5165
+ if (expired) {
5166
+ observedInboundMessageIds.delete(expired);
5167
+ inboundReplyMetadataByMessageKey.delete(expired);
5168
+ }
5169
+ }
5170
+ }, rememberObservedInboundMessageKeys2 = function(messageKeys) {
5171
+ for (const messageKey of messageKeys) {
5172
+ rememberObservedInboundMessageId2(messageKey);
5173
+ }
5174
+ }, rememberObservedInboundContentFingerprint2 = function(contentFingerprint) {
5175
+ if (!contentFingerprint) return;
5176
+ if (!observedInboundContentFingerprints.has(contentFingerprint)) {
5177
+ observedInboundContentFingerprints.add(contentFingerprint);
5178
+ observedInboundContentFingerprintOrder.push(contentFingerprint);
5179
+ }
5180
+ while (observedInboundContentFingerprintOrder.length > MAX_OBSERVED_INBOUND_MESSAGE_IDS) {
5181
+ const expired = observedInboundContentFingerprintOrder.shift();
5182
+ if (expired) observedInboundContentFingerprints.delete(expired);
5183
+ }
5184
+ }, rememberPendingSparseInboundContentFingerprint2 = function(contentFingerprint) {
5185
+ if (!contentFingerprint) return;
5186
+ if (!pendingSparseInboundContentFingerprints.has(contentFingerprint)) {
5187
+ pendingSparseInboundContentFingerprints.add(contentFingerprint);
5188
+ pendingSparseInboundContentFingerprintOrder.push(contentFingerprint);
5189
+ }
5190
+ while (pendingSparseInboundContentFingerprintOrder.length > MAX_OBSERVED_INBOUND_MESSAGE_IDS) {
5191
+ const expired = pendingSparseInboundContentFingerprintOrder.shift();
5192
+ if (expired) pendingSparseInboundContentFingerprints.delete(expired);
5193
+ }
5194
+ }, consumePendingSparseInboundContentFingerprint2 = function(contentFingerprint) {
5195
+ if (!contentFingerprint || !pendingSparseInboundContentFingerprints.has(contentFingerprint)) {
5196
+ return false;
5197
+ }
5198
+ pendingSparseInboundContentFingerprints.delete(contentFingerprint);
5199
+ const index = pendingSparseInboundContentFingerprintOrder.indexOf(contentFingerprint);
5200
+ if (index >= 0) pendingSparseInboundContentFingerprintOrder.splice(index, 1);
5201
+ return true;
5202
+ }, rememberInboundReplyMetadata2 = function(messageKeys, metadata) {
5203
+ if (!metadata?.replyToBody?.trim()) return;
5204
+ for (const messageKey of messageKeys) {
5205
+ if (!inboundReplyMetadataByMessageKey.has(messageKey)) {
5206
+ inboundReplyMetadataKeyOrder.push(messageKey);
5207
+ }
5208
+ inboundReplyMetadataByMessageKey.set(messageKey, metadata);
5209
+ }
5210
+ while (inboundReplyMetadataKeyOrder.length > MAX_OBSERVED_INBOUND_MESSAGE_IDS) {
5211
+ const expired = inboundReplyMetadataKeyOrder.shift();
5212
+ if (expired && !observedInboundMessageIds.has(expired)) {
5213
+ inboundReplyMetadataByMessageKey.delete(expired);
5214
+ }
5215
+ }
5216
+ }, getInboundReplyMetadata2 = function(messageKeys) {
5217
+ for (const messageKey of messageKeys) {
5218
+ const metadata = inboundReplyMetadataByMessageKey.get(messageKey);
5219
+ if (metadata?.replyToBody?.trim()) return metadata;
5220
+ }
5221
+ return null;
5222
+ }, rememberObservedInlineExplicitCaptureKey2 = function(noteKey) {
5223
+ if (!observedInlineExplicitCaptureKeys.has(noteKey)) {
5224
+ observedInlineExplicitCaptureKeys.add(noteKey);
5225
+ observedInlineExplicitCaptureKeyOrder.push(noteKey);
5226
+ }
5227
+ while (observedInlineExplicitCaptureKeyOrder.length > MAX_OBSERVED_INLINE_EXPLICIT_CAPTURE_KEYS) {
5228
+ const expired = observedInlineExplicitCaptureKeyOrder.shift();
5229
+ if (expired) observedInlineExplicitCaptureKeys.delete(expired);
5230
+ }
5231
+ }, buildInlineExplicitCaptureDedupeKey2 = function(messageKey, note) {
5232
+ if (!messageKey) return null;
5233
+ return `${messageKey}:inline-memory-note:${createHash2("sha256").update(JSON.stringify(note)).digest("hex")}`;
5234
+ }, resolveStoredCodexThreadId2 = function(sessionKey) {
4888
5235
  const threadId = codexThreadBySession.get(sessionKey);
4889
5236
  return typeof threadId === "string" && threadId.length > 0 ? threadId : null;
4890
5237
  }, resolveStoredCodexBufferKey2 = function(sessionKey) {
@@ -5171,7 +5518,7 @@ Keep the reflection grounded in the evidence below.
5171
5518
  const lowered = prompt.trim().toLowerCase();
5172
5519
  return lowered.startsWith("read heartbeat.md") || lowered.startsWith("run the following periodic tasks");
5173
5520
  };
5174
- var 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, buildMemoryContextLines = buildMemoryContextLines2, renderMemoryContextPrompt = renderMemoryContextPrompt2, isHeartbeatTrigger = isHeartbeatTrigger2, resolveHeartbeatPromptCandidates = resolveHeartbeatPromptCandidates2, matchHeartbeatEntry = matchHeartbeatEntry2, looksLikeHeartbeatPrompt = looksLikeHeartbeatPrompt2;
5521
+ 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, buildMemoryContextLines = buildMemoryContextLines2, renderMemoryContextPrompt = renderMemoryContextPrompt2, isHeartbeatTrigger = isHeartbeatTrigger2, resolveHeartbeatPromptCandidates = resolveHeartbeatPromptCandidates2, matchHeartbeatEntry = matchHeartbeatEntry2, looksLikeHeartbeatPrompt = looksLikeHeartbeatPrompt2;
5175
5522
  const hooksPolicy = readPluginHooksPolicy(api.config, serviceId);
5176
5523
  const promptInjectionAllowed = coerceRawConfigBoolean(hooksPolicy?.allowPromptInjection) !== false;
5177
5524
  const useMemoryPromptSection = sdkCaps.hasRegisterMemoryPromptSection && typeof api.registerMemoryPromptSection === "function" && promptInjectionAllowed;
@@ -5183,7 +5530,62 @@ Keep the reflection grounded in the evidence below.
5183
5530
  const codexSessionsByThread = /* @__PURE__ */ new Map();
5184
5531
  const codexSessionsByBufferKey = /* @__PURE__ */ new Map();
5185
5532
  const codexMessageCountByBufferKey = /* @__PURE__ */ new Map();
5533
+ const observedInboundMessageIds = /* @__PURE__ */ new Set();
5534
+ const observedInboundMessageIdOrder = [];
5535
+ const observedInboundContentFingerprints = /* @__PURE__ */ new Set();
5536
+ const observedInboundContentFingerprintOrder = [];
5537
+ const pendingSparseInboundContentFingerprints = /* @__PURE__ */ new Set();
5538
+ const pendingSparseInboundContentFingerprintOrder = [];
5539
+ const inboundReplyMetadataByMessageKey = /* @__PURE__ */ new Map();
5540
+ const inboundReplyMetadataKeyOrder = [];
5541
+ const observedInlineExplicitCaptureKeys = /* @__PURE__ */ new Set();
5542
+ const observedInlineExplicitCaptureKeyOrder = [];
5186
5543
  let codexCompactionModeLogged = false;
5544
+ async function processInlineExplicitCaptureNotes(notes, messageKeys) {
5545
+ let processed = 0;
5546
+ for (const note of notes) {
5547
+ const noteKeys = (messageKeys ?? []).map((messageKey) => buildInlineExplicitCaptureDedupeKey2(messageKey, note)).filter((noteKey) => typeof noteKey === "string");
5548
+ if (noteKeys.length > 0 && noteKeys.some((noteKey) => observedInlineExplicitCaptureKeys.has(noteKey))) {
5549
+ continue;
5550
+ }
5551
+ try {
5552
+ await (0, explicit_capture_exports.persistExplicitCapture)(
5553
+ orchestrator,
5554
+ (0, explicit_capture_exports.validateExplicitCaptureInput)(note),
5555
+ "inline"
5556
+ );
5557
+ orchestrator.requestQmdMaintenanceForTool("inline.memory_note");
5558
+ for (const noteKey of noteKeys) {
5559
+ rememberObservedInlineExplicitCaptureKey2(noteKey);
5560
+ }
5561
+ processed += 1;
5562
+ } catch (error) {
5563
+ try {
5564
+ const queued = await (0, explicit_capture_exports.queueExplicitCaptureForReview)(
5565
+ orchestrator,
5566
+ note,
5567
+ "inline",
5568
+ error
5569
+ );
5570
+ orchestrator.requestQmdMaintenanceForTool(
5571
+ "inline.memory_note.review"
5572
+ );
5573
+ for (const noteKey of noteKeys) {
5574
+ rememberObservedInlineExplicitCaptureKey2(noteKey);
5575
+ }
5576
+ processed += 1;
5577
+ logger_exports.log.warn(
5578
+ `explicit inline capture queued for review: ${queued.id}${queued.duplicateOf ? ` (duplicate of ${queued.duplicateOf})` : ""}`
5579
+ );
5580
+ } catch (queueError) {
5581
+ logger_exports.log.warn(
5582
+ `explicit inline capture rejected: ${error}; review queue fallback failed: ${queueError}`
5583
+ );
5584
+ }
5585
+ }
5586
+ }
5587
+ return processed;
5588
+ }
5187
5589
  async function flushAndForgetCodexThreadOnProviderSwitch(sessionKey, sessionIdentity) {
5188
5590
  if (sessionIdentity.isCodex || !sessionIdentity.previousCodexThreadId) {
5189
5591
  return;
@@ -6007,6 +6409,86 @@ Keep the reflection grounded in the evidence below.
6007
6409
  const capabilityDesc = typeof api.registerMemoryCapability === "function" ? `memory capability with publicArtifacts provider${builderDesc}` : "split memory runtime/flush-plan surfaces";
6008
6410
  logger_exports.log.info(`registered ${capabilityDesc}`);
6009
6411
  }
6412
+ if (cfg.openclawMessageReceivedCaptureEnabled) {
6413
+ api.on(
6414
+ "message_received",
6415
+ async (event, ctx) => {
6416
+ if (cfg.heartbeat.enabled && cfg.heartbeat.gateExtractionDuringHeartbeat && isHeartbeatTrigger2(event, ctx)) {
6417
+ logger_exports.log.debug(
6418
+ `message_received: skipping transcript capture during heartbeat run for ${ctx?.sessionKey ?? "default"}`
6419
+ );
6420
+ return;
6421
+ }
6422
+ const content = typeof event.content === "string" ? event.content.trim() : "";
6423
+ if (content.length === 0) return;
6424
+ const sessionKey = normalizeOptionalString(ctx.sessionKey) ?? normalizeOptionalString(event.sessionKey) ?? "default";
6425
+ const inboundMessageKeys = getOpenClawMessageDedupeKeys(event, event, ctx, sessionKey);
6426
+ if (inboundMessageKeys.some((key) => observedInboundMessageIds.has(key))) return;
6427
+ const metadata = buildOpenClawMessageMetadata(event, event, ctx, cfg);
6428
+ const inboundReplyHintMetadata = cfg.openclawReplyMetadataExtractionHintsEnabled ? buildOpenClawMessageMetadata(event, event, ctx, {
6429
+ openclawReplyMetadataCaptureEnabled: true
6430
+ }) : metadata;
6431
+ const eventDate = typeof event.timestamp === "number" && Number.isFinite(event.timestamp) ? new Date(event.timestamp) : /* @__PURE__ */ new Date();
6432
+ const timestamp = Number.isFinite(eventDate.getTime()) ? eventDate.toISOString() : (/* @__PURE__ */ new Date()).toISOString();
6433
+ const cleaned = cleanOpenClawUserMessage(content);
6434
+ const inlineCaptureEnabled = (0, explicit_capture_exports.shouldProcessInlineExplicitCapture)(
6435
+ orchestrator.config
6436
+ );
6437
+ const explicitNotes = inlineCaptureEnabled ? (0, explicit_capture_exports.parseInlineExplicitCaptureNotes)(cleaned) : [];
6438
+ const transcriptContent = inlineCaptureEnabled && (0, explicit_capture_exports.hasInlineExplicitCaptureMarkup)(cleaned) ? (0, explicit_capture_exports.stripInlineExplicitCaptureNotes)(cleaned) : cleaned;
6439
+ const inboundContentFingerprint = buildOpenClawInboundContentFingerprint(
6440
+ transcriptContent,
6441
+ event,
6442
+ event,
6443
+ ctx,
6444
+ sessionKey
6445
+ );
6446
+ const sparseInboundContentFingerprint = buildOpenClawSparseInboundContentFingerprint(
6447
+ transcriptContent,
6448
+ sessionKey
6449
+ );
6450
+ if (inboundContentFingerprint && observedInboundContentFingerprints.has(inboundContentFingerprint)) {
6451
+ return;
6452
+ }
6453
+ const inlineCaptureDedupeKeys = inboundMessageKeys.length > 0 ? inboundMessageKeys : inboundContentFingerprint ? [inboundContentFingerprint] : sparseInboundContentFingerprint ? [sparseInboundContentFingerprint] : [];
6454
+ const processedExplicitNotes = explicitNotes.length > 0 ? await processInlineExplicitCaptureNotes(
6455
+ explicitNotes,
6456
+ inlineCaptureDedupeKeys
6457
+ ) : 0;
6458
+ if (!orchestrator.config.transcriptEnabled || transcriptContent.length === 0) {
6459
+ rememberInboundReplyMetadata2(inboundMessageKeys, inboundReplyHintMetadata);
6460
+ if (processedExplicitNotes > 0) {
6461
+ rememberObservedInboundMessageKeys2(inboundMessageKeys);
6462
+ rememberObservedInboundContentFingerprint2(inboundContentFingerprint);
6463
+ if (inboundMessageKeys.length === 0) {
6464
+ rememberPendingSparseInboundContentFingerprint2(sparseInboundContentFingerprint);
6465
+ }
6466
+ }
6467
+ return;
6468
+ }
6469
+ try {
6470
+ await orchestrator.transcript.append({
6471
+ timestamp,
6472
+ role: "user",
6473
+ content: transcriptContent,
6474
+ sessionKey,
6475
+ turnId: crypto.randomUUID(),
6476
+ ...metadata ? { metadata } : {}
6477
+ });
6478
+ if (inboundMessageKeys.length > 0) {
6479
+ rememberObservedInboundMessageKeys2(inboundMessageKeys);
6480
+ rememberInboundReplyMetadata2(inboundMessageKeys, inboundReplyHintMetadata);
6481
+ }
6482
+ rememberObservedInboundContentFingerprint2(inboundContentFingerprint);
6483
+ if (inboundMessageKeys.length === 0) {
6484
+ rememberPendingSparseInboundContentFingerprint2(sparseInboundContentFingerprint);
6485
+ }
6486
+ } catch (err) {
6487
+ logger_exports.log.debug(`message_received transcript append failed: ${err}`);
6488
+ }
6489
+ }
6490
+ );
6491
+ }
6010
6492
  api.on(
6011
6493
  "agent_end",
6012
6494
  async (event, ctx) => {
@@ -6089,52 +6571,58 @@ Keep the reflection grounded in the evidence below.
6089
6571
  const role = rawRole;
6090
6572
  const content = extractTextContent(msg);
6091
6573
  if (content.length < 10) continue;
6092
- const cleaned = role === "user" ? cleanUserMessage(content) : content;
6574
+ const cleaned = role === "user" ? cleanOpenClawUserMessage(content) : content;
6093
6575
  const inlineCaptureEnabled = (0, explicit_capture_exports.shouldProcessInlineExplicitCapture)(
6094
6576
  orchestrator.config
6095
6577
  );
6096
6578
  const explicitNotes = inlineCaptureEnabled ? (0, explicit_capture_exports.parseInlineExplicitCaptureNotes)(cleaned) : [];
6097
6579
  const stripped = inlineCaptureEnabled && (0, explicit_capture_exports.hasInlineExplicitCaptureMarkup)(cleaned) ? (0, explicit_capture_exports.stripInlineExplicitCaptureNotes)(cleaned) : cleaned;
6098
- for (const note of explicitNotes) {
6099
- try {
6100
- await (0, explicit_capture_exports.persistExplicitCapture)(
6101
- orchestrator,
6102
- (0, explicit_capture_exports.validateExplicitCaptureInput)(note),
6103
- "inline"
6104
- );
6105
- orchestrator.requestQmdMaintenanceForTool("inline.memory_note");
6106
- } catch (error) {
6107
- try {
6108
- const queued = await (0, explicit_capture_exports.queueExplicitCaptureForReview)(
6109
- orchestrator,
6110
- note,
6111
- "inline",
6112
- error
6113
- );
6114
- orchestrator.requestQmdMaintenanceForTool(
6115
- "inline.memory_note.review"
6116
- );
6117
- logger_exports.log.warn(
6118
- `explicit inline capture queued for review: ${queued.id}${queued.duplicateOf ? ` (duplicate of ${queued.duplicateOf})` : ""}`
6119
- );
6120
- } catch (queueError) {
6121
- logger_exports.log.warn(
6122
- `explicit inline capture rejected: ${error}; review queue fallback failed: ${queueError}`
6123
- );
6124
- }
6125
- }
6126
- }
6127
- if (orchestrator.config.transcriptEnabled && stripped.length > 0) {
6580
+ const messageMetadata = buildOpenClawMessageMetadata(
6581
+ msg,
6582
+ event,
6583
+ ctx,
6584
+ cfg
6585
+ );
6586
+ const messageDedupeKeys = getOpenClawMessageDedupeKeys(msg, event, ctx, sessionKey);
6587
+ const messageContentFingerprint = buildOpenClawInboundContentFingerprint(
6588
+ stripped,
6589
+ msg,
6590
+ event,
6591
+ ctx,
6592
+ sessionKey
6593
+ );
6594
+ const sparseMessageContentFingerprint = buildOpenClawSparseInboundContentFingerprint(stripped, sessionKey);
6595
+ const cachedReplyHintMetadata = role === "user" && cfg.openclawReplyMetadataExtractionHintsEnabled ? getInboundReplyMetadata2(messageDedupeKeys) : null;
6596
+ const replyHintMetadata = cfg.openclawReplyMetadataExtractionHintsEnabled ? cachedReplyHintMetadata ?? buildOpenClawMessageMetadata(msg, event, ctx, {
6597
+ openclawReplyMetadataCaptureEnabled: true
6598
+ }) : messageMetadata;
6599
+ const messageDedupeKey = messageDedupeKeys[0];
6600
+ const sparseInboundAlreadyCaptured = role === "user" && messageDedupeKeys.length === 0 && consumePendingSparseInboundContentFingerprint2(sparseMessageContentFingerprint);
6601
+ const transcriptAlreadyCaptured = role === "user" && (messageDedupeKeys.length > 0 && messageDedupeKeys.some((key) => observedInboundMessageIds.has(key)) || sparseInboundAlreadyCaptured || messageContentFingerprint !== null && observedInboundContentFingerprints.has(messageContentFingerprint));
6602
+ const inlineCaptureDedupeKeys = messageDedupeKeys.length > 0 ? messageDedupeKeys : messageContentFingerprint ? [messageContentFingerprint] : sparseMessageContentFingerprint ? [sparseMessageContentFingerprint] : [];
6603
+ await processInlineExplicitCaptureNotes(
6604
+ explicitNotes,
6605
+ inlineCaptureDedupeKeys
6606
+ );
6607
+ if (orchestrator.config.transcriptEnabled && stripped.length > 0 && !transcriptAlreadyCaptured) {
6128
6608
  await orchestrator.transcript.append({
6129
6609
  timestamp: eventTimestamp,
6130
6610
  role,
6131
6611
  content: stripped,
6132
6612
  sessionKey,
6133
- turnId: crypto.randomUUID()
6613
+ turnId: crypto.randomUUID(),
6614
+ ...messageMetadata ? { metadata: messageMetadata } : {}
6134
6615
  });
6616
+ if (role === "user") {
6617
+ if (messageDedupeKey) {
6618
+ rememberObservedInboundMessageKeys2(messageDedupeKeys);
6619
+ }
6620
+ rememberObservedInboundContentFingerprint2(messageContentFingerprint);
6621
+ }
6135
6622
  }
6136
6623
  if (stripped.length > 0) {
6137
- await orchestrator.processTurn(role, stripped, sessionKey, {
6624
+ const extractionContent = role === "user" && cfg.openclawReplyMetadataExtractionHintsEnabled ? withReplyExtractionHint(stripped, replyHintMetadata) : stripped;
6625
+ await orchestrator.processTurn(role, extractionContent, sessionKey, {
6138
6626
  bufferKey: resolveExtractionBufferKey2(
6139
6627
  sessionKey,
6140
6628
  sessionIdentity.logicalSessionKey
@@ -6143,7 +6631,7 @@ Keep the reflection grounded in the evidence below.
6143
6631
  providerThreadId: sessionIdentity.providerThreadId,
6144
6632
  turnFingerprint: buildTurnFingerprint({
6145
6633
  role,
6146
- content: stripped,
6634
+ content: extractionContent,
6147
6635
  logicalSessionKey: sessionIdentity.logicalSessionKey,
6148
6636
  providerThreadId: sessionIdentity.providerThreadId,
6149
6637
  maxContentChars: cfg.extractionMaxTurnChars,
@@ -6990,6 +7478,10 @@ Keep the reflection grounded in the evidence below.
6990
7478
  stopHeartbeatWatcher = null;
6991
7479
  removeDreamingObserver?.();
6992
7480
  removeDreamingObserver = null;
7481
+ const unregisterOpenClawHostEmbeddingProvider = globalThis[keys.HOST_EMBEDDING_UNREGISTER];
7482
+ unregisterOpenClawHostEmbeddingProvider?.();
7483
+ delete globalThis[keys.HOST_EMBEDDING_UNREGISTER];
7484
+ delete globalThis[keys.HOST_EMBEDDING_SIGNATURE];
6993
7485
  delete globalThis[keys.ACCESS_HTTP_SERVER];
6994
7486
  delete globalThis[keys.ACCESS_HTTP_AUTH_STATE];
6995
7487
  delete globalThis[keys.ACCESS_SERVICE];
@@ -7025,6 +7517,97 @@ function extractTextContent(msg) {
7025
7517
  }
7026
7518
  return "";
7027
7519
  }
7520
+ function buildOpenClawMessageMetadata(message, event, ctx, cfg) {
7521
+ if (!cfg.openclawReplyMetadataCaptureEnabled) return null;
7522
+ const metadata = {};
7523
+ const messageId = getOpenClawMessageId(message, event, ctx);
7524
+ if (messageId) metadata.messageId = truncateMetadataValue(messageId, 512);
7525
+ const threadId = normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId);
7526
+ if (threadId) metadata.threadId = truncateMetadataValue(threadId, 512);
7527
+ const replyToId = normalizeOptionalString(message.replyToId) ?? normalizeOptionalString(event.replyToId) ?? normalizeOptionalString(ctx.replyToId);
7528
+ if (replyToId) metadata.replyToId = truncateMetadataValue(replyToId, 512);
7529
+ const replyToBody = normalizeOptionalString(message.replyToBody) ?? normalizeOptionalString(event.replyToBody) ?? normalizeOptionalString(ctx.replyToBody);
7530
+ if (replyToBody) metadata.replyToBody = truncateMetadataValue(replyToBody, 1e3);
7531
+ const replyToSender = normalizeOptionalString(message.replyToSender) ?? normalizeOptionalString(event.replyToSender) ?? normalizeOptionalString(ctx.replyToSender);
7532
+ if (replyToSender) metadata.replyToSender = truncateMetadataValue(replyToSender, 256);
7533
+ return Object.keys(metadata).length > 0 ? metadata : null;
7534
+ }
7535
+ function getOpenClawMessageId(message, event, ctx) {
7536
+ const messageId = normalizeOptionalString(message.messageId) ?? normalizeOptionalString(event.messageId) ?? normalizeOptionalString(ctx.messageId);
7537
+ return messageId ? truncateMetadataValue(messageId, 512) : void 0;
7538
+ }
7539
+ function getOpenClawMessageDedupeKeys(message, event, ctx, sessionKey) {
7540
+ const messageId = getOpenClawMessageId(message, event, ctx);
7541
+ if (!messageId) return [];
7542
+ const sessionScope = normalizeOptionalString(message.sessionKey) ?? normalizeOptionalString(event.sessionKey) ?? normalizeOptionalString(ctx.sessionKey) ?? sessionKey;
7543
+ const threadScope = truncateMetadataValue(
7544
+ normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
7545
+ 512
7546
+ );
7547
+ const runScope = truncateMetadataValue(
7548
+ normalizeOptionalString(message.runId) ?? normalizeOptionalString(event.runId) ?? normalizeOptionalString(ctx.runId) ?? "",
7549
+ 512
7550
+ );
7551
+ const sessionPart = truncateMetadataValue(sessionScope, 512);
7552
+ const dedupeScopes = /* @__PURE__ */ new Set();
7553
+ if (threadScope) dedupeScopes.add(threadScope);
7554
+ if (runScope) dedupeScopes.add(runScope);
7555
+ dedupeScopes.add("");
7556
+ return [...dedupeScopes].map((scope) => `${sessionPart}\0${scope}\0${messageId}`);
7557
+ }
7558
+ function buildOpenClawInboundContentFingerprint(content, message, event, ctx, sessionKey) {
7559
+ const normalizedContent = content.trim();
7560
+ if (!normalizedContent) return null;
7561
+ const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
7562
+ const runScope = truncateMetadataValue(
7563
+ normalizeOptionalString(message.runId) ?? normalizeOptionalString(event.runId) ?? normalizeOptionalString(ctx.runId) ?? "",
7564
+ 512
7565
+ );
7566
+ const rawTimestamp = normalizeOptionalString(message.timestamp) ?? normalizeOptionalString(event.timestamp) ?? normalizeOptionalString(ctx.timestamp) ?? (typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? String(message.timestamp) : void 0) ?? (typeof event.timestamp === "number" && Number.isFinite(event.timestamp) ? String(event.timestamp) : void 0) ?? (typeof ctx.timestamp === "number" && Number.isFinite(ctx.timestamp) ? String(ctx.timestamp) : void 0);
7567
+ const timestampScope = rawTimestamp ? truncateMetadataValue(rawTimestamp, 512) : "";
7568
+ if (!runScope && !timestampScope) return null;
7569
+ const threadScope = truncateMetadataValue(
7570
+ normalizeThreadId(message.threadId) ?? normalizeThreadId(event.threadId) ?? normalizeThreadId(ctx.threadId) ?? "",
7571
+ 512
7572
+ );
7573
+ const contentHash = createHash2("sha256").update(normalizedContent).digest("hex");
7574
+ return [
7575
+ sessionPart,
7576
+ "content",
7577
+ threadScope,
7578
+ runScope,
7579
+ timestampScope,
7580
+ contentHash
7581
+ ].join("\0");
7582
+ }
7583
+ function buildOpenClawSparseInboundContentFingerprint(content, sessionKey) {
7584
+ const normalizedContent = content.trim();
7585
+ if (!normalizedContent) return null;
7586
+ const sessionPart = truncateMetadataValue(sessionKey || "default", 512);
7587
+ const contentHash = createHash2("sha256").update(normalizedContent).digest("hex");
7588
+ return `${sessionPart}\0sparse-content\0${contentHash}`;
7589
+ }
7590
+ function withReplyExtractionHint(content, metadata) {
7591
+ const replyBody = metadata?.replyToBody?.trim();
7592
+ if (!replyBody) return content;
7593
+ const sender = metadata?.replyToSender?.trim();
7594
+ const prefix = sender ? `Reply context from ${sender}: ${replyBody}` : `Reply context: ${replyBody}`;
7595
+ return `${prefix}
7596
+
7597
+ Current message: ${content}`;
7598
+ }
7599
+ function normalizeOptionalString(value) {
7600
+ if (typeof value !== "string") return void 0;
7601
+ const trimmed = value.trim();
7602
+ return trimmed.length > 0 ? trimmed : void 0;
7603
+ }
7604
+ function normalizeThreadId(value) {
7605
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
7606
+ return normalizeOptionalString(value);
7607
+ }
7608
+ function truncateMetadataValue(value, maxChars) {
7609
+ return value.length <= maxChars ? value : value.slice(0, maxChars);
7610
+ }
7028
7611
 
7029
7612
  // src/bridge.ts
7030
7613
  import fs from "fs";
@@ -7273,4 +7856,4 @@ async function checkDaemonHealth(host, port) {
7273
7856
  }
7274
7857
  }
7275
7858
  var export_loadDaySummaryPrompt = day_summary_exports.loadDaySummaryPrompt;
7276
- export { checkDaemonHealth, src_default as default, detectBridgeMode, listRemnicPublicArtifacts, export_loadDaySummaryPrompt as loadDaySummaryPrompt, loadHourlySummaryCronJobsData, parseHourlySummaryCronJobsData };
7859
+ export { checkDaemonHealth, src_default as default, detectBridgeMode, embedWithOpenClawProvider, listRemnicPublicArtifacts, export_loadDaySummaryPrompt as loadDaySummaryPrompt, loadHourlySummaryCronJobsData, loadOpenClawMemoryEmbeddingSdk, parseHourlySummaryCronJobsData, selectOpenClawMemoryEmbeddingSdk };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-remnic",
3
3
  "name": "Remnic OpenClaw Plugin",
4
- "version": "9.3.563",
4
+ "version": "9.3.564",
5
5
  "kind": "memory",
6
6
  "description": "Local semantic memory for OpenClaw with bundled Remnic core runtime. Requires plugins.slots.memory set to this plugin id for hooks to fire.",
7
7
  "setup": {
@@ -371,6 +371,19 @@
371
371
  "default": "auto",
372
372
  "description": "Embedding provider selection for semantic fallback"
373
373
  },
374
+ "hostEmbeddingProviderEnabled": {
375
+ "type": "boolean",
376
+ "default": true,
377
+ "description": "Prefer OpenClaw host-registered embedding providers for Remnic's semantic fallback and embedded vector backends when the OpenClaw SDK exposes them. Falls back to Remnic's existing embedding provider path on older hosts or provider setup failures."
378
+ },
379
+ "hostEmbeddingProviderId": {
380
+ "type": "string",
381
+ "description": "Optional OpenClaw embedding provider adapter id to use. Leave unset for automatic selection from OpenClaw's memory/generic embedding provider registry."
382
+ },
383
+ "hostEmbeddingProviderModel": {
384
+ "type": "string",
385
+ "description": "Optional embedding model id passed to the selected OpenClaw host embedding provider."
386
+ },
374
387
  "embeddingFallbackModel": {
375
388
  "type": "string",
376
389
  "description": "Optional model identifier for embedding fallback requests. Defaults to localLlmModel for legacy installs."
@@ -801,6 +814,26 @@
801
814
  "default": 600,
802
815
  "description": "Maximum snippet size returned by the OpenClaw memory tool adapters."
803
816
  },
817
+ "openclawMessageReceivedCaptureEnabled": {
818
+ "type": "boolean",
819
+ "default": true,
820
+ "description": "Capture OpenClaw message_received hook content into transcripts when that hook is emitted by the host. Older OpenClaw versions that never emit the hook continue through agent_end capture."
821
+ },
822
+ "openclawReplyMetadataCaptureEnabled": {
823
+ "type": "boolean",
824
+ "default": true,
825
+ "description": "Persist bounded OpenClaw messageId, threadId, replyToId, replyToBody, and replyToSender fields in transcript metadata when available."
826
+ },
827
+ "openclawReplyMetadataExtractionHintsEnabled": {
828
+ "type": "boolean",
829
+ "default": false,
830
+ "description": "When true, prepend bounded quoted-reply context to user turns before Remnic extraction. Leave false to store reply metadata without changing extraction behavior."
831
+ },
832
+ "openclawChannelEnvelopeCleaningEnabled": {
833
+ "type": "boolean",
834
+ "default": true,
835
+ "description": "Use OpenClaw's canonical chat-channel envelope prefixes when the SDK exposes plugin-sdk/chat-channel-ids, while keeping the legacy OpenClaw-only cleaner on older hosts."
836
+ },
804
837
  "sessionTogglesEnabled": {
805
838
  "type": "boolean",
806
839
  "default": true,
@@ -4883,6 +4916,41 @@
4883
4916
  "label": "Enable QMD",
4884
4917
  "help": "Enable QMD for memory search/indexing"
4885
4918
  },
4919
+ "hostEmbeddingProviderEnabled": {
4920
+ "label": "Use Host Embeddings",
4921
+ "advanced": true,
4922
+ "help": "Prefer OpenClaw's registered embedding providers when available; Remnic falls back automatically."
4923
+ },
4924
+ "hostEmbeddingProviderId": {
4925
+ "label": "Host Embedding Provider",
4926
+ "advanced": true,
4927
+ "placeholder": "openai-compatible"
4928
+ },
4929
+ "hostEmbeddingProviderModel": {
4930
+ "label": "Host Embedding Model",
4931
+ "advanced": true,
4932
+ "placeholder": "text-embedding-3-small"
4933
+ },
4934
+ "openclawMessageReceivedCaptureEnabled": {
4935
+ "label": "Capture Inbound Messages",
4936
+ "advanced": true,
4937
+ "help": "Use OpenClaw message_received transcript capture when the host emits it."
4938
+ },
4939
+ "openclawReplyMetadataCaptureEnabled": {
4940
+ "label": "Capture Reply Metadata",
4941
+ "advanced": true,
4942
+ "help": "Store bounded message/thread/reply fields in transcript metadata."
4943
+ },
4944
+ "openclawReplyMetadataExtractionHintsEnabled": {
4945
+ "label": "Use Reply Extraction Hints",
4946
+ "advanced": true,
4947
+ "help": "Include bounded quoted-reply context in extraction prompts. Off by default."
4948
+ },
4949
+ "openclawChannelEnvelopeCleaningEnabled": {
4950
+ "label": "Clean Channel Envelopes",
4951
+ "advanced": true,
4952
+ "help": "Use OpenClaw's canonical channel envelope prefixes when available."
4953
+ },
4886
4954
  "qmdCollection": {
4887
4955
  "label": "QMD Collection",
4888
4956
  "advanced": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/plugin-openclaw",
3
- "version": "9.3.563",
3
+ "version": "9.3.564",
4
4
  "description": "OpenClaw adapter for Remnic memory with bundled @remnic/core runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,11 +28,11 @@
28
28
  "./dist/index.js"
29
29
  ],
30
30
  "compat": {
31
- "pluginApi": ">=2026.4.1 || 2026.4.7-1 || 2026.4.9-beta.1 || 2026.4.11-beta.1 || 2026.4.12-beta.1 || 2026.4.14-beta.1 || 2026.4.15-beta.1 || 2026.4.15-beta.2 || 2026.4.19-beta.1 || 2026.4.19-beta.2 || 2026.4.20-beta.1 || 2026.4.20-beta.2 || 2026.4.22-beta.1 || 2026.4.23-beta.1 || 2026.4.23-beta.2 || 2026.4.23-beta.3 || 2026.4.23-beta.4 || 2026.4.23-beta.5 || 2026.4.23-beta.6 || 2026.4.24-beta.1 || 2026.4.24-beta.2 || 2026.4.24-beta.3 || 2026.4.24-beta.4 || 2026.4.24-beta.5 || 2026.4.24-beta.6 || 2026.4.25-beta.1 || 2026.4.25-beta.2 || 2026.4.25-beta.3 || 2026.4.25-beta.4 || 2026.4.25-beta.5 || 2026.4.25-beta.6 || 2026.4.25-beta.7 || 2026.4.25-beta.8 || 2026.4.25-beta.9 || 2026.4.25-beta.10 || 2026.4.25-beta.11 || 2026.4.26-beta.1 || 2026.4.27-beta.1 || 2026.4.29-beta.1 || 2026.4.29-beta.2 || 2026.4.29-beta.3 || 2026.4.29-beta.4 || 2026.4.30-beta.1 || 2026.5.2-beta.1 || 2026.5.2-beta.2 || 2026.5.2-beta.3 || 2026.5.3-1 || 2026.5.3-beta.1 || 2026.5.3-beta.2 || 2026.5.3-beta.3 || 2026.5.3-beta.4 || 2026.5.4-beta.1 || 2026.5.4-beta.2 || 2026.5.4-beta.3 || 2026.5.5-beta.1 || 2026.5.5-beta.2 || 2026.5.6-beta.1 || 2026.5.7-beta.1 || 2026.5.9-beta.1 || 2026.5.10-beta.1 || 2026.5.10-beta.2 || 2026.5.10-beta.3 || 2026.5.10-beta.4 || 2026.5.10-beta.5 || 2026.5.10-beta.6 || 2026.5.12-beta.1 || 2026.5.12-beta.2 || 2026.5.12-beta.3 || 2026.5.12-beta.4 || 2026.5.12-beta.5 || 2026.5.12-beta.6 || 2026.5.12-beta.7 || 2026.5.12-beta.8 || 2026.5.14-beta.1 || 2026.5.14-beta.2 || 2026.5.16-beta.1 || 2026.5.16-beta.2 || 2026.5.16-beta.3 || 2026.5.16-beta.4 || 2026.5.16-beta.5 || 2026.5.16-beta.6 || 2026.5.16-beta.7 || 2026.5.18-beta.1 || 2026.5.19-alpha.1 || 2026.5.19-beta.1 || 2026.5.19-beta.2 || 2026.5.20-beta.1 || 2026.5.20-beta.2 || 2026.5.21-alpha.1 || 2026.5.21-beta.1 || 2026.5.22-beta.1 || 2026.5.23-alpha.1 || 2026.5.24-alpha.1 || 2026.5.24-beta.1 || 2026.5.24-beta.2 || 2026.5.25-alpha.1 || 2026.5.25-alpha.2 || 2026.5.25-beta.1 || 2026.5.26-beta.1 || 2026.5.26-beta.2 || 2026.5.27-alpha.1 || 2026.5.27-beta.1 || 2026.5.28-alpha.1 || 2026.5.28-beta.1 || 2026.5.28-beta.2 || 2026.5.28-beta.3 || 2026.5.28-beta.4 || 2026.5.29-alpha.1 || 2026.5.30-beta.1 || 2026.5.30-beta.2 || 2026.5.31-alpha.1 || 2026.5.31-beta.1 || 2026.5.31-beta.2 || 2026.5.31-beta.3 || 2026.5.31-beta.4 || 2026.6.1-alpha.1 || 2026.6.1-alpha.2 || 2026.6.1-alpha.3 || 2026.6.1-beta.1 || 2026.6.1-beta.2 || 2026.6.2-alpha.1"
31
+ "pluginApi": ">=2026.4.1 || 2026.4.7-1 || 2026.4.9-beta.1 || 2026.4.11-beta.1 || 2026.4.12-beta.1 || 2026.4.14-beta.1 || 2026.4.15-beta.1 || 2026.4.15-beta.2 || 2026.4.19-beta.1 || 2026.4.19-beta.2 || 2026.4.20-beta.1 || 2026.4.20-beta.2 || 2026.4.22-beta.1 || 2026.4.23-beta.1 || 2026.4.23-beta.2 || 2026.4.23-beta.3 || 2026.4.23-beta.4 || 2026.4.23-beta.5 || 2026.4.23-beta.6 || 2026.4.24-beta.1 || 2026.4.24-beta.2 || 2026.4.24-beta.3 || 2026.4.24-beta.4 || 2026.4.24-beta.5 || 2026.4.24-beta.6 || 2026.4.25-beta.1 || 2026.4.25-beta.2 || 2026.4.25-beta.3 || 2026.4.25-beta.4 || 2026.4.25-beta.5 || 2026.4.25-beta.6 || 2026.4.25-beta.7 || 2026.4.25-beta.8 || 2026.4.25-beta.9 || 2026.4.25-beta.10 || 2026.4.25-beta.11 || 2026.4.26-beta.1 || 2026.4.27-beta.1 || 2026.4.29-beta.1 || 2026.4.29-beta.2 || 2026.4.29-beta.3 || 2026.4.29-beta.4 || 2026.4.30-beta.1 || 2026.5.2-beta.1 || 2026.5.2-beta.2 || 2026.5.2-beta.3 || 2026.5.3-1 || 2026.5.3-beta.1 || 2026.5.3-beta.2 || 2026.5.3-beta.3 || 2026.5.3-beta.4 || 2026.5.4-beta.1 || 2026.5.4-beta.2 || 2026.5.4-beta.3 || 2026.5.5-beta.1 || 2026.5.5-beta.2 || 2026.5.6-beta.1 || 2026.5.7-beta.1 || 2026.5.9-beta.1 || 2026.5.10-beta.1 || 2026.5.10-beta.2 || 2026.5.10-beta.3 || 2026.5.10-beta.4 || 2026.5.10-beta.5 || 2026.5.10-beta.6 || 2026.5.12-beta.1 || 2026.5.12-beta.2 || 2026.5.12-beta.3 || 2026.5.12-beta.4 || 2026.5.12-beta.5 || 2026.5.12-beta.6 || 2026.5.12-beta.7 || 2026.5.12-beta.8 || 2026.5.14-beta.1 || 2026.5.14-beta.2 || 2026.5.16-beta.1 || 2026.5.16-beta.2 || 2026.5.16-beta.3 || 2026.5.16-beta.4 || 2026.5.16-beta.5 || 2026.5.16-beta.6 || 2026.5.16-beta.7 || 2026.5.18-beta.1 || 2026.5.19-alpha.1 || 2026.5.19-beta.1 || 2026.5.19-beta.2 || 2026.5.20-beta.1 || 2026.5.20-beta.2 || 2026.5.21-alpha.1 || 2026.5.21-beta.1 || 2026.5.22-beta.1 || 2026.5.23-alpha.1 || 2026.5.24-alpha.1 || 2026.5.24-beta.1 || 2026.5.24-beta.2 || 2026.5.25-alpha.1 || 2026.5.25-alpha.2 || 2026.5.25-beta.1 || 2026.5.26-beta.1 || 2026.5.26-beta.2 || 2026.5.27-alpha.1 || 2026.5.27-beta.1 || 2026.5.28-alpha.1 || 2026.5.28-beta.1 || 2026.5.28-beta.2 || 2026.5.28-beta.3 || 2026.5.28-beta.4 || 2026.5.29-alpha.1 || 2026.5.30-beta.1 || 2026.5.30-beta.2 || 2026.5.31-alpha.1 || 2026.5.31-beta.1 || 2026.5.31-beta.2 || 2026.5.31-beta.3 || 2026.5.31-beta.4 || 2026.6.1-alpha.1 || 2026.6.1-alpha.2 || 2026.6.1-alpha.3 || 2026.6.1-beta.1 || 2026.6.1-beta.2 || 2026.6.2-alpha.1 || 2026.6.2-alpha.2"
32
32
  },
33
33
  "build": {
34
- "openclawVersion": "2026.6.2-alpha.1",
35
- "pluginSdkVersion": "2026.6.2-alpha.1"
34
+ "openclawVersion": "2026.6.2-alpha.2",
35
+ "pluginSdkVersion": "2026.6.2-alpha.2"
36
36
  },
37
37
  "install": {
38
38
  "clawhubSpec": "clawhub:@remnic/plugin-openclaw",
@@ -72,17 +72,17 @@
72
72
  "dependencies": {
73
73
  "@sinclair/typebox": "^0.34.0",
74
74
  "openai": "^6.0.0",
75
- "@remnic/core": "^9.3.563"
75
+ "@remnic/core": "^9.3.564"
76
76
  },
77
77
  "peerDependencies": {
78
- "openclaw": ">=2026.4.1 || 2026.4.7-1 || 2026.4.9-beta.1 || 2026.4.11-beta.1 || 2026.4.12-beta.1 || 2026.4.14-beta.1 || 2026.4.15-beta.1 || 2026.4.15-beta.2 || 2026.4.19-beta.1 || 2026.4.19-beta.2 || 2026.4.20-beta.1 || 2026.4.20-beta.2 || 2026.4.22-beta.1 || 2026.4.23-beta.1 || 2026.4.23-beta.2 || 2026.4.23-beta.3 || 2026.4.23-beta.4 || 2026.4.23-beta.5 || 2026.4.23-beta.6 || 2026.4.24-beta.1 || 2026.4.24-beta.2 || 2026.4.24-beta.3 || 2026.4.24-beta.4 || 2026.4.24-beta.5 || 2026.4.24-beta.6 || 2026.4.25-beta.1 || 2026.4.25-beta.2 || 2026.4.25-beta.3 || 2026.4.25-beta.4 || 2026.4.25-beta.5 || 2026.4.25-beta.6 || 2026.4.25-beta.7 || 2026.4.25-beta.8 || 2026.4.25-beta.9 || 2026.4.25-beta.10 || 2026.4.25-beta.11 || 2026.4.26-beta.1 || 2026.4.27-beta.1 || 2026.4.29-beta.1 || 2026.4.29-beta.2 || 2026.4.29-beta.3 || 2026.4.29-beta.4 || 2026.4.30-beta.1 || 2026.5.2-beta.1 || 2026.5.2-beta.2 || 2026.5.2-beta.3 || 2026.5.3-1 || 2026.5.3-beta.1 || 2026.5.3-beta.2 || 2026.5.3-beta.3 || 2026.5.3-beta.4 || 2026.5.4-beta.1 || 2026.5.4-beta.2 || 2026.5.4-beta.3 || 2026.5.5-beta.1 || 2026.5.5-beta.2 || 2026.5.6-beta.1 || 2026.5.7-beta.1 || 2026.5.9-beta.1 || 2026.5.10-beta.1 || 2026.5.10-beta.2 || 2026.5.10-beta.3 || 2026.5.10-beta.4 || 2026.5.10-beta.5 || 2026.5.10-beta.6 || 2026.5.12-beta.1 || 2026.5.12-beta.2 || 2026.5.12-beta.3 || 2026.5.12-beta.4 || 2026.5.12-beta.5 || 2026.5.12-beta.6 || 2026.5.12-beta.7 || 2026.5.12-beta.8 || 2026.5.14-beta.1 || 2026.5.14-beta.2 || 2026.5.16-beta.1 || 2026.5.16-beta.2 || 2026.5.16-beta.3 || 2026.5.16-beta.4 || 2026.5.16-beta.5 || 2026.5.16-beta.6 || 2026.5.16-beta.7 || 2026.5.18-beta.1 || 2026.5.19-alpha.1 || 2026.5.19-beta.1 || 2026.5.19-beta.2 || 2026.5.20-beta.1 || 2026.5.20-beta.2 || 2026.5.21-alpha.1 || 2026.5.21-beta.1 || 2026.5.22-beta.1 || 2026.5.23-alpha.1 || 2026.5.24-alpha.1 || 2026.5.24-beta.1 || 2026.5.24-beta.2 || 2026.5.25-alpha.1 || 2026.5.25-alpha.2 || 2026.5.25-beta.1 || 2026.5.26-beta.1 || 2026.5.26-beta.2 || 2026.5.27-alpha.1 || 2026.5.27-beta.1 || 2026.5.28-alpha.1 || 2026.5.28-beta.1 || 2026.5.28-beta.2 || 2026.5.28-beta.3 || 2026.5.28-beta.4 || 2026.5.29-alpha.1 || 2026.5.30-beta.1 || 2026.5.30-beta.2 || 2026.5.31-alpha.1 || 2026.5.31-beta.1 || 2026.5.31-beta.2 || 2026.5.31-beta.3 || 2026.5.31-beta.4 || 2026.6.1-alpha.1 || 2026.6.1-alpha.2 || 2026.6.1-alpha.3 || 2026.6.1-beta.1 || 2026.6.1-beta.2 || 2026.6.2-alpha.1"
78
+ "openclaw": ">=2026.4.1 || 2026.4.7-1 || 2026.4.9-beta.1 || 2026.4.11-beta.1 || 2026.4.12-beta.1 || 2026.4.14-beta.1 || 2026.4.15-beta.1 || 2026.4.15-beta.2 || 2026.4.19-beta.1 || 2026.4.19-beta.2 || 2026.4.20-beta.1 || 2026.4.20-beta.2 || 2026.4.22-beta.1 || 2026.4.23-beta.1 || 2026.4.23-beta.2 || 2026.4.23-beta.3 || 2026.4.23-beta.4 || 2026.4.23-beta.5 || 2026.4.23-beta.6 || 2026.4.24-beta.1 || 2026.4.24-beta.2 || 2026.4.24-beta.3 || 2026.4.24-beta.4 || 2026.4.24-beta.5 || 2026.4.24-beta.6 || 2026.4.25-beta.1 || 2026.4.25-beta.2 || 2026.4.25-beta.3 || 2026.4.25-beta.4 || 2026.4.25-beta.5 || 2026.4.25-beta.6 || 2026.4.25-beta.7 || 2026.4.25-beta.8 || 2026.4.25-beta.9 || 2026.4.25-beta.10 || 2026.4.25-beta.11 || 2026.4.26-beta.1 || 2026.4.27-beta.1 || 2026.4.29-beta.1 || 2026.4.29-beta.2 || 2026.4.29-beta.3 || 2026.4.29-beta.4 || 2026.4.30-beta.1 || 2026.5.2-beta.1 || 2026.5.2-beta.2 || 2026.5.2-beta.3 || 2026.5.3-1 || 2026.5.3-beta.1 || 2026.5.3-beta.2 || 2026.5.3-beta.3 || 2026.5.3-beta.4 || 2026.5.4-beta.1 || 2026.5.4-beta.2 || 2026.5.4-beta.3 || 2026.5.5-beta.1 || 2026.5.5-beta.2 || 2026.5.6-beta.1 || 2026.5.7-beta.1 || 2026.5.9-beta.1 || 2026.5.10-beta.1 || 2026.5.10-beta.2 || 2026.5.10-beta.3 || 2026.5.10-beta.4 || 2026.5.10-beta.5 || 2026.5.10-beta.6 || 2026.5.12-beta.1 || 2026.5.12-beta.2 || 2026.5.12-beta.3 || 2026.5.12-beta.4 || 2026.5.12-beta.5 || 2026.5.12-beta.6 || 2026.5.12-beta.7 || 2026.5.12-beta.8 || 2026.5.14-beta.1 || 2026.5.14-beta.2 || 2026.5.16-beta.1 || 2026.5.16-beta.2 || 2026.5.16-beta.3 || 2026.5.16-beta.4 || 2026.5.16-beta.5 || 2026.5.16-beta.6 || 2026.5.16-beta.7 || 2026.5.18-beta.1 || 2026.5.19-alpha.1 || 2026.5.19-beta.1 || 2026.5.19-beta.2 || 2026.5.20-beta.1 || 2026.5.20-beta.2 || 2026.5.21-alpha.1 || 2026.5.21-beta.1 || 2026.5.22-beta.1 || 2026.5.23-alpha.1 || 2026.5.24-alpha.1 || 2026.5.24-beta.1 || 2026.5.24-beta.2 || 2026.5.25-alpha.1 || 2026.5.25-alpha.2 || 2026.5.25-beta.1 || 2026.5.26-beta.1 || 2026.5.26-beta.2 || 2026.5.27-alpha.1 || 2026.5.27-beta.1 || 2026.5.28-alpha.1 || 2026.5.28-beta.1 || 2026.5.28-beta.2 || 2026.5.28-beta.3 || 2026.5.28-beta.4 || 2026.5.29-alpha.1 || 2026.5.30-beta.1 || 2026.5.30-beta.2 || 2026.5.31-alpha.1 || 2026.5.31-beta.1 || 2026.5.31-beta.2 || 2026.5.31-beta.3 || 2026.5.31-beta.4 || 2026.6.1-alpha.1 || 2026.6.1-alpha.2 || 2026.6.1-alpha.3 || 2026.6.1-beta.1 || 2026.6.1-beta.2 || 2026.6.2-alpha.1 || 2026.6.2-alpha.2"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@openclaw/plugin-inspector": "0.3.10",
82
82
  "acorn": "^8.16.0",
83
83
  "tsup": "^8.5.1",
84
84
  "typescript": "^5.9.3",
85
- "@remnic/core": "^9.3.563"
85
+ "@remnic/core": "^9.3.564"
86
86
  },
87
87
  "license": "MIT",
88
88
  "repository": {