@remnic/plugin-openclaw 1.0.13 → 1.0.14

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 CHANGED
@@ -601,6 +601,9 @@ var MEMORY_OS_PRESETS = {
601
601
  contextCompressionActionsEnabled: true,
602
602
  compressionGuidelineLearningEnabled: true,
603
603
  compressionGuidelineSemanticRefinementEnabled: true,
604
+ explicitCueRecallEnabled: true,
605
+ explicitCueRecallMaxChars: 3200,
606
+ lcmEnabled: true,
604
607
  maxProactiveQuestionsPerExtraction: 4,
605
608
  maxCompressionTokensPerHour: 3e3,
606
609
  behaviorLoopAutoTuneEnabled: true
@@ -1897,6 +1900,9 @@ function parseConfig(raw) {
1897
1900
  temporalMemoryTreeEnabled: cfg.temporalMemoryTreeEnabled === true,
1898
1901
  tmtHourlyMinMemories: typeof cfg.tmtHourlyMinMemories === "number" ? cfg.tmtHourlyMinMemories : 3,
1899
1902
  tmtSummaryMaxTokens: typeof cfg.tmtSummaryMaxTokens === "number" ? cfg.tmtSummaryMaxTokens : 300,
1903
+ explicitCueRecallEnabled: coerceBool(cfg.explicitCueRecallEnabled) === true,
1904
+ explicitCueRecallMaxChars: coerceNumber(cfg.explicitCueRecallMaxChars) !== void 0 ? Math.max(0, Math.floor(coerceNumber(cfg.explicitCueRecallMaxChars))) : 2400,
1905
+ explicitCueRecallMaxReferences: coerceNumber(cfg.explicitCueRecallMaxReferences) !== void 0 ? Math.max(0, Math.floor(coerceNumber(cfg.explicitCueRecallMaxReferences))) : 24,
1900
1906
  // Lossless Context Management (LCM)
1901
1907
  lcmEnabled: cfg.lcmEnabled === true,
1902
1908
  lcmLeafBatchSize: typeof cfg.lcmLeafBatchSize === "number" ? Math.max(2, Math.floor(cfg.lcmLeafBatchSize)) : 8,
@@ -2254,6 +2260,12 @@ function buildDefaultRecallPipeline(cfg) {
2254
2260
  enabled: cfg.sharedContextEnabled === true,
2255
2261
  maxChars: typeof cfg.sharedContextMaxInjectChars === "number" ? Math.max(0, Math.floor(cfg.sharedContextMaxInjectChars)) : 4e3
2256
2262
  },
2263
+ {
2264
+ id: "explicit-cue",
2265
+ enabled: coerceBool(cfg.explicitCueRecallEnabled) === true,
2266
+ maxChars: coerceNumber(cfg.explicitCueRecallMaxChars) !== void 0 ? Math.max(0, Math.floor(coerceNumber(cfg.explicitCueRecallMaxChars))) : 2400,
2267
+ maxResults: coerceNumber(cfg.explicitCueRecallMaxReferences) !== void 0 ? Math.max(0, Math.floor(coerceNumber(cfg.explicitCueRecallMaxReferences))) : 24
2268
+ },
2257
2269
  {
2258
2270
  id: "profile",
2259
2271
  enabled: true,
@@ -23087,6 +23099,630 @@ async function readRecentEntityTranscriptEntries(transcriptEntriesPromise, recen
23087
23099
  }
23088
23100
  var entityRecentTranscriptLookbackHours = RECENT_TRANSCRIPT_LOOKBACK_HOURS;
23089
23101
 
23102
+ // ../remnic-core/src/evidence-pack.ts
23103
+ var DEFAULT_MAX_ITEM_CHARS = 1200;
23104
+ function buildEvidencePack(items, options) {
23105
+ const budget = normalizePositiveInteger(options.maxChars);
23106
+ if (budget <= 0 || items.length === 0) {
23107
+ return "";
23108
+ }
23109
+ const maxItemChars = normalizePositiveInteger(
23110
+ options.maxItemChars ?? DEFAULT_MAX_ITEM_CHARS
23111
+ );
23112
+ if (maxItemChars <= 0) {
23113
+ return "";
23114
+ }
23115
+ const title = options.title ?? "Evidence";
23116
+ const lines = [`## ${title}`];
23117
+ const seenIds = /* @__PURE__ */ new Set();
23118
+ const seenContent = /* @__PURE__ */ new Set();
23119
+ let used = lines[0].length;
23120
+ for (const item of items) {
23121
+ const content = item.content.trim();
23122
+ if (!content) continue;
23123
+ const id = item.id ?? evidenceItemFallbackId(item);
23124
+ if (id && seenIds.has(id)) continue;
23125
+ const contentKey = normalizeEvidenceContent(content);
23126
+ if (seenContent.has(contentKey)) continue;
23127
+ const label = formatEvidenceLabel(item);
23128
+ const clipped = clipText(content, maxItemChars);
23129
+ const block = `${label}: ${clipped}`;
23130
+ const separatorLength = lines.length > 0 ? 2 : 0;
23131
+ const remaining = budget - used - separatorLength;
23132
+ if (remaining <= 0) break;
23133
+ const finalBlock = block.length > remaining ? clipText(block, remaining) : block;
23134
+ if (!finalBlock.trim()) break;
23135
+ lines.push(finalBlock);
23136
+ used += separatorLength + finalBlock.length;
23137
+ if (id) seenIds.add(id);
23138
+ seenContent.add(contentKey);
23139
+ }
23140
+ return lines.length === 1 ? "" : lines.join("\n\n");
23141
+ }
23142
+ function normalizePositiveInteger(value) {
23143
+ if (!Number.isFinite(value) || value <= 0) {
23144
+ return 0;
23145
+ }
23146
+ return Math.floor(value);
23147
+ }
23148
+ function evidenceItemFallbackId(item) {
23149
+ if (item.sessionId && typeof item.turnIndex === "number") {
23150
+ return `${item.sessionId}:${item.turnIndex}`;
23151
+ }
23152
+ return void 0;
23153
+ }
23154
+ function normalizeEvidenceContent(content) {
23155
+ return content.toLowerCase().replace(/\s+/g, " ").trim();
23156
+ }
23157
+ function formatEvidenceLabel(item) {
23158
+ const parts = [];
23159
+ if (item.sessionId) parts.push(item.sessionId);
23160
+ if (typeof item.turnIndex === "number") parts.push(`turn ${item.turnIndex}`);
23161
+ if (item.role) parts.push(item.role);
23162
+ if (typeof item.score === "number" && Number.isFinite(item.score)) {
23163
+ parts.push(`score ${item.score.toFixed(3)}`);
23164
+ }
23165
+ return parts.length > 0 ? `[${parts.join(", ")}]` : "[evidence]";
23166
+ }
23167
+ function clipText(text, maxChars) {
23168
+ if (text.length <= maxChars) {
23169
+ return text;
23170
+ }
23171
+ if (maxChars <= 1) {
23172
+ return text.slice(0, maxChars);
23173
+ }
23174
+ if (maxChars <= 3) {
23175
+ return text.slice(0, maxChars);
23176
+ }
23177
+ return `${text.slice(0, maxChars - 3).trimEnd()}...`;
23178
+ }
23179
+
23180
+ // ../remnic-core/src/explicit-cue-recall.ts
23181
+ var DEFAULT_MAX_CHARS = 2400;
23182
+ var DEFAULT_MAX_ITEM_CHARS2 = 1200;
23183
+ var DEFAULT_MAX_REFERENCES = 24;
23184
+ var REFERENCE_SCAN_TOKEN_FACTOR = 3;
23185
+ var TURN_REFERENCE_WINDOW_RADIUS = 0;
23186
+ var LEXICAL_CUE_WINDOW_RADIUS = 1;
23187
+ var LEXICAL_CUE_SEARCH_LIMIT = 3;
23188
+ var LEXICAL_CUE_MAX_TOKENS = 400;
23189
+ var LATEST_STATE_CUES = /* @__PURE__ */ new Set([
23190
+ "as of",
23191
+ "currently",
23192
+ "latest",
23193
+ "most recent",
23194
+ "newest",
23195
+ "now",
23196
+ "updated",
23197
+ "changed",
23198
+ "change"
23199
+ ]);
23200
+ var RELATIVE_TEMPORAL_CUES = [
23201
+ "as of",
23202
+ "most recent",
23203
+ "last time",
23204
+ "last week",
23205
+ "last month",
23206
+ "last year",
23207
+ "last session",
23208
+ "last conversation",
23209
+ "next time",
23210
+ "next week",
23211
+ "next month",
23212
+ "next year",
23213
+ "next session",
23214
+ "next conversation",
23215
+ "previous time",
23216
+ "previous week",
23217
+ "previous month",
23218
+ "previous year",
23219
+ "previous session",
23220
+ "previous conversation",
23221
+ "prior time",
23222
+ "prior week",
23223
+ "prior month",
23224
+ "prior year",
23225
+ "prior session",
23226
+ "prior conversation",
23227
+ "today",
23228
+ "yesterday",
23229
+ "tomorrow",
23230
+ "tonight",
23231
+ "earlier",
23232
+ "later",
23233
+ "recently",
23234
+ "previously",
23235
+ "currently",
23236
+ "now",
23237
+ "latest",
23238
+ "newest",
23239
+ "oldest",
23240
+ "earliest",
23241
+ "before",
23242
+ "after",
23243
+ "since",
23244
+ "updated",
23245
+ "changed",
23246
+ "change"
23247
+ ];
23248
+ var SPEAKER_NAME_STOPWORDS = /* @__PURE__ */ new Set([
23249
+ "A",
23250
+ "According",
23251
+ "An",
23252
+ "And",
23253
+ "Are",
23254
+ "As",
23255
+ "At",
23256
+ "Before",
23257
+ "Can",
23258
+ "Compare",
23259
+ "Could",
23260
+ "Did",
23261
+ "Do",
23262
+ "Does",
23263
+ "For",
23264
+ "From",
23265
+ "Had",
23266
+ "Has",
23267
+ "Have",
23268
+ "How",
23269
+ "In",
23270
+ "Is",
23271
+ "It",
23272
+ "Of",
23273
+ "On",
23274
+ "Or",
23275
+ "Please",
23276
+ "Review",
23277
+ "Step",
23278
+ "Tell",
23279
+ "The",
23280
+ "To",
23281
+ "Turn",
23282
+ "Use",
23283
+ "Was",
23284
+ "Were",
23285
+ "What",
23286
+ "When",
23287
+ "Where",
23288
+ "Which",
23289
+ "Who",
23290
+ "Why",
23291
+ "Will",
23292
+ "Would"
23293
+ ]);
23294
+ var QUESTION_SLOT_STOPWORDS = /* @__PURE__ */ new Set([
23295
+ "answer",
23296
+ "choice",
23297
+ "did",
23298
+ "does",
23299
+ "do",
23300
+ "is",
23301
+ "should",
23302
+ "single",
23303
+ "the",
23304
+ "user",
23305
+ "was",
23306
+ "were"
23307
+ ]);
23308
+ async function buildExplicitCueRecallSection(options) {
23309
+ const engine = options.engine;
23310
+ const query = options.query.trim();
23311
+ const maxChars = normalizePositiveInteger2(options.maxChars, DEFAULT_MAX_CHARS);
23312
+ if (!engine || query.length === 0 || maxChars <= 0) {
23313
+ return "";
23314
+ }
23315
+ const maxReferences = normalizePositiveInteger2(
23316
+ options.maxReferences,
23317
+ DEFAULT_MAX_REFERENCES
23318
+ );
23319
+ if (maxReferences <= 0) {
23320
+ return "";
23321
+ }
23322
+ const evidenceItems = [];
23323
+ const seenTurns = /* @__PURE__ */ new Set();
23324
+ await collectTurnReferenceEvidence({
23325
+ engine,
23326
+ sessionId: options.sessionId,
23327
+ query,
23328
+ maxReferences,
23329
+ evidenceItems,
23330
+ seenTurns
23331
+ });
23332
+ await collectLexicalCueEvidence({
23333
+ engine,
23334
+ sessionId: options.sessionId,
23335
+ query,
23336
+ maxReferences,
23337
+ evidenceItems,
23338
+ seenTurns
23339
+ });
23340
+ return buildEvidencePack(evidenceItems, {
23341
+ title: "Explicit Cue Evidence",
23342
+ maxChars,
23343
+ maxItemChars: normalizePositiveInteger2(
23344
+ options.maxItemChars,
23345
+ DEFAULT_MAX_ITEM_CHARS2
23346
+ )
23347
+ });
23348
+ }
23349
+ async function collectTurnReferenceEvidence(options) {
23350
+ if (!options.sessionId) {
23351
+ return;
23352
+ }
23353
+ const references = collectExplicitTurnReferences(options.query).slice(
23354
+ 0,
23355
+ options.maxReferences
23356
+ );
23357
+ if (references.length === 0) {
23358
+ return;
23359
+ }
23360
+ const windows = /* @__PURE__ */ new Map();
23361
+ for (const reference of references) {
23362
+ for (const center of candidateTurnIndexesForReference(reference)) {
23363
+ if (center < 0) {
23364
+ continue;
23365
+ }
23366
+ const fromTurn = Math.max(0, center - TURN_REFERENCE_WINDOW_RADIUS);
23367
+ const toTurn = center + TURN_REFERENCE_WINDOW_RADIUS;
23368
+ windows.set(`${fromTurn}:${toTurn}`, { fromTurn, toTurn });
23369
+ }
23370
+ }
23371
+ for (const window of [...windows.values()].sort(
23372
+ (left, right) => left.fromTurn - right.fromTurn || left.toTurn - right.toTurn
23373
+ )) {
23374
+ const expanded = await options.engine.expandContext(
23375
+ options.sessionId,
23376
+ window.fromTurn,
23377
+ window.toTurn,
23378
+ 2e3
23379
+ );
23380
+ appendExpandedEvidence(
23381
+ options.evidenceItems,
23382
+ options.seenTurns,
23383
+ options.sessionId,
23384
+ expanded
23385
+ );
23386
+ }
23387
+ }
23388
+ async function collectLexicalCueEvidence(options) {
23389
+ const cues = collectLexicalCues(options.query).slice(0, options.maxReferences);
23390
+ const preferLatest = hasLatestStateIntent(options.query);
23391
+ for (const cue of cues) {
23392
+ const results = sortLexicalCueResults(
23393
+ await options.engine.searchContextFull(
23394
+ cue,
23395
+ LEXICAL_CUE_SEARCH_LIMIT,
23396
+ options.sessionId
23397
+ ),
23398
+ preferLatest
23399
+ );
23400
+ for (const result of results) {
23401
+ const windowRadius = preferLatest ? 0 : LEXICAL_CUE_WINDOW_RADIUS;
23402
+ const fromTurn = Math.max(0, result.turn_index - windowRadius);
23403
+ const toTurn = result.turn_index + windowRadius;
23404
+ const expanded = await options.engine.expandContext(
23405
+ result.session_id,
23406
+ fromTurn,
23407
+ toTurn,
23408
+ LEXICAL_CUE_MAX_TOKENS
23409
+ );
23410
+ if (expanded.length === 0) {
23411
+ appendEvidenceItem(options.evidenceItems, options.seenTurns, {
23412
+ id: `${result.session_id}:${result.turn_index}`,
23413
+ sessionId: result.session_id,
23414
+ turnIndex: result.turn_index,
23415
+ role: result.role,
23416
+ content: result.content,
23417
+ ...typeof result.score === "number" ? { score: result.score } : {}
23418
+ });
23419
+ continue;
23420
+ }
23421
+ appendExpandedEvidence(
23422
+ options.evidenceItems,
23423
+ options.seenTurns,
23424
+ result.session_id,
23425
+ expanded
23426
+ );
23427
+ }
23428
+ }
23429
+ }
23430
+ function appendExpandedEvidence(evidenceItems, seenTurns, sessionId, expanded) {
23431
+ for (const message of expanded) {
23432
+ appendEvidenceItem(evidenceItems, seenTurns, {
23433
+ id: `${sessionId}:${message.turn_index}`,
23434
+ sessionId,
23435
+ turnIndex: message.turn_index,
23436
+ role: message.role,
23437
+ content: message.content
23438
+ });
23439
+ }
23440
+ }
23441
+ function appendEvidenceItem(evidenceItems, seenTurns, item) {
23442
+ if (seenTurns.has(item.id)) {
23443
+ return;
23444
+ }
23445
+ seenTurns.add(item.id);
23446
+ evidenceItems.push(item);
23447
+ }
23448
+ function collectExplicitTurnReferences(query) {
23449
+ const references = /* @__PURE__ */ new Map();
23450
+ const addReference = (value, label) => {
23451
+ const existing = references.get(String(value));
23452
+ references.set(String(value), {
23453
+ number: value,
23454
+ includeDirectTurn: (existing?.includeDirectTurn ?? false) || label === "turn"
23455
+ });
23456
+ };
23457
+ const tokens = tokenizeReferenceQuery(query);
23458
+ for (let index = 0; index < tokens.length; index += 1) {
23459
+ const label = normalizeReferenceLabel(tokens[index]);
23460
+ if (!label) {
23461
+ continue;
23462
+ }
23463
+ const parsed = parseReferenceNumbers(tokens, index + 1);
23464
+ for (const number of parsed.numbers) {
23465
+ addReference(number, label);
23466
+ }
23467
+ index = Math.max(index, parsed.nextIndex - 1);
23468
+ }
23469
+ return [...references.values()].sort((left, right) => left.number - right.number);
23470
+ }
23471
+ function collectLexicalCues(query) {
23472
+ const cues = /* @__PURE__ */ new Set();
23473
+ for (const match of query.matchAll(/\b[A-Za-z][A-Za-z0-9]{0,12}\d+:\d+\b/g)) {
23474
+ cues.add(match[0]);
23475
+ }
23476
+ for (const match of query.matchAll(/\b\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}(?::\d{2})?Z?)?\b/g)) {
23477
+ cues.add(match[0]);
23478
+ }
23479
+ for (const cue of collectTemporalLexicalCues(query)) {
23480
+ cues.add(cue);
23481
+ }
23482
+ for (const cue of collectQuestionSlotCues(query)) {
23483
+ cues.add(cue);
23484
+ }
23485
+ for (const match of query.matchAll(/\b(?:session|source|chat|plan|task|event|file|tool)[_-][A-Za-z0-9][A-Za-z0-9_.:-]{0,80}\b/gi)) {
23486
+ cues.add(match[0]);
23487
+ }
23488
+ for (const match of query.matchAll(/\b[A-Z][a-z]{1,30}(?:\s+[A-Z][a-z]{1,30}){0,2}\b/g)) {
23489
+ const value = normalizeSpeakerNameCue(match[0]);
23490
+ if (value) {
23491
+ cues.add(value);
23492
+ }
23493
+ }
23494
+ for (const match of query.matchAll(/\[([A-Za-z0-9][A-Za-z0-9_.:/ -]{1,80})\]/g)) {
23495
+ const value = match[1]?.trim();
23496
+ if (value) {
23497
+ cues.add(value);
23498
+ }
23499
+ }
23500
+ return [...cues].sort((left, right) => left.localeCompare(right));
23501
+ }
23502
+ function collectQuestionSlotCues(query) {
23503
+ const cues = /* @__PURE__ */ new Set();
23504
+ for (const match of query.matchAll(
23505
+ /\b(?:what|which)\s+([a-z][a-z0-9_-]{2,30})\s+(?:does|do|did|is|are|was|were|should|would|could|can|will)\b/gi
23506
+ )) {
23507
+ const value = match[1]?.toLowerCase();
23508
+ if (value && !QUESTION_SLOT_STOPWORDS.has(value)) {
23509
+ cues.add(value);
23510
+ }
23511
+ }
23512
+ return [...cues].sort((left, right) => left.localeCompare(right));
23513
+ }
23514
+ function collectTemporalLexicalCues(query) {
23515
+ const cues = /* @__PURE__ */ new Set();
23516
+ const normalizedQuery = query.toLowerCase().replace(/\s+/g, " ");
23517
+ for (const cue of RELATIVE_TEMPORAL_CUES) {
23518
+ let searchFrom = 0;
23519
+ while (searchFrom < normalizedQuery.length) {
23520
+ const index = normalizedQuery.indexOf(cue, searchFrom);
23521
+ if (index < 0) {
23522
+ break;
23523
+ }
23524
+ const afterIndex = index + cue.length;
23525
+ if (isTemporalCueBoundary(normalizedQuery[index - 1]) && isTemporalCueBoundary(normalizedQuery[afterIndex])) {
23526
+ cues.add(cue);
23527
+ break;
23528
+ }
23529
+ searchFrom = afterIndex;
23530
+ }
23531
+ }
23532
+ return [...cues].sort((left, right) => left.localeCompare(right));
23533
+ }
23534
+ function hasLatestStateIntent(query) {
23535
+ return collectTemporalLexicalCues(query).some(
23536
+ (cue) => LATEST_STATE_CUES.has(cue)
23537
+ );
23538
+ }
23539
+ function sortLexicalCueResults(results, preferLatest) {
23540
+ return [...results].sort((left, right) => {
23541
+ if (preferLatest) {
23542
+ const sessionOrder2 = left.session_id.localeCompare(right.session_id);
23543
+ if (sessionOrder2 !== 0) {
23544
+ return sessionOrder2;
23545
+ }
23546
+ const turnOrder = right.turn_index - left.turn_index;
23547
+ if (turnOrder !== 0) {
23548
+ return turnOrder;
23549
+ }
23550
+ return (right.score ?? 0) - (left.score ?? 0);
23551
+ }
23552
+ const scoreDelta = (right.score ?? 0) - (left.score ?? 0);
23553
+ if (scoreDelta !== 0) {
23554
+ return scoreDelta;
23555
+ }
23556
+ const sessionOrder = left.session_id.localeCompare(right.session_id);
23557
+ if (sessionOrder !== 0) {
23558
+ return sessionOrder;
23559
+ }
23560
+ return left.turn_index - right.turn_index;
23561
+ });
23562
+ }
23563
+ function normalizeSpeakerNameCue(value) {
23564
+ const words = value.trim().split(/\s+/).filter(Boolean);
23565
+ while (words.length > 0 && SPEAKER_NAME_STOPWORDS.has(words[0])) {
23566
+ words.shift();
23567
+ }
23568
+ while (words.length > 0 && SPEAKER_NAME_STOPWORDS.has(words[words.length - 1])) {
23569
+ words.pop();
23570
+ }
23571
+ return words.length > 0 ? words.join(" ") : void 0;
23572
+ }
23573
+ function isTemporalCueBoundary(char) {
23574
+ if (!char) {
23575
+ return true;
23576
+ }
23577
+ return !isAsciiLetterOrDigit(char);
23578
+ }
23579
+ function tokenizeReferenceQuery(query) {
23580
+ const tokens = [];
23581
+ let current = "";
23582
+ const flushCurrent = () => {
23583
+ if (current) {
23584
+ tokens.push(current);
23585
+ current = "";
23586
+ }
23587
+ };
23588
+ for (const char of query) {
23589
+ if (isAsciiLetterOrDigit(char)) {
23590
+ current += char;
23591
+ continue;
23592
+ }
23593
+ flushCurrent();
23594
+ if (char === "#" || char === ",") {
23595
+ tokens.push(char);
23596
+ } else if (isReferenceDash(char)) {
23597
+ tokens.push("-");
23598
+ }
23599
+ }
23600
+ flushCurrent();
23601
+ return tokens;
23602
+ }
23603
+ function parseReferenceNumbers(tokens, startIndex) {
23604
+ const numbers = [];
23605
+ let lastNumber;
23606
+ let pendingRangeStart;
23607
+ let index = startIndex;
23608
+ const scanEnd = Math.min(
23609
+ tokens.length,
23610
+ startIndex + DEFAULT_MAX_REFERENCES * REFERENCE_SCAN_TOKEN_FACTOR
23611
+ );
23612
+ for (; index < scanEnd; index += 1) {
23613
+ const token = tokens[index];
23614
+ const normalized = token.toLowerCase();
23615
+ const value = parseNonNegativeIntegerToken(token);
23616
+ if (value !== void 0) {
23617
+ if (pendingRangeStart !== void 0) {
23618
+ numbers.push(...expandReferenceRange(pendingRangeStart, value));
23619
+ pendingRangeStart = void 0;
23620
+ } else {
23621
+ numbers.push(value);
23622
+ }
23623
+ lastNumber = value;
23624
+ continue;
23625
+ }
23626
+ if (normalized === "#" || normalized === "number" || normalized === ",") {
23627
+ continue;
23628
+ }
23629
+ if (normalized === "-" || normalized === "to" || normalized === "through" || normalized === "thru") {
23630
+ if (lastNumber !== void 0) {
23631
+ if (numbers[numbers.length - 1] === lastNumber) {
23632
+ numbers.pop();
23633
+ }
23634
+ pendingRangeStart = lastNumber;
23635
+ }
23636
+ continue;
23637
+ }
23638
+ if (normalized === "and" && numbers.length > 0) {
23639
+ continue;
23640
+ }
23641
+ if (normalizeReferenceLabel(token)) {
23642
+ break;
23643
+ }
23644
+ break;
23645
+ }
23646
+ if (pendingRangeStart !== void 0) {
23647
+ numbers.push(pendingRangeStart);
23648
+ }
23649
+ return {
23650
+ numbers: [...new Set(numbers)],
23651
+ nextIndex: index
23652
+ };
23653
+ }
23654
+ function expandReferenceRange(start, end) {
23655
+ const low = Math.min(start, end);
23656
+ const high = Math.max(start, end);
23657
+ if (high - low + 1 > DEFAULT_MAX_REFERENCES) {
23658
+ return [start, end];
23659
+ }
23660
+ const values = [];
23661
+ for (let value = low; value <= high; value += 1) {
23662
+ values.push(value);
23663
+ }
23664
+ return values;
23665
+ }
23666
+ function normalizeReferenceLabel(token) {
23667
+ const normalized = token?.toLowerCase();
23668
+ switch (normalized) {
23669
+ case "step":
23670
+ case "steps":
23671
+ return "step";
23672
+ case "turn":
23673
+ case "turns":
23674
+ return "turn";
23675
+ case "action":
23676
+ case "actions":
23677
+ return "action";
23678
+ case "observation":
23679
+ case "observations":
23680
+ return "observation";
23681
+ default:
23682
+ return void 0;
23683
+ }
23684
+ }
23685
+ function candidateTurnIndexesForReference(reference) {
23686
+ const candidates = /* @__PURE__ */ new Set();
23687
+ if (reference.includeDirectTurn) {
23688
+ for (let offset = -1; offset <= 1; offset += 1) {
23689
+ candidates.add(reference.number + offset);
23690
+ }
23691
+ }
23692
+ const pairedBase = reference.number * 2;
23693
+ for (let offset = -2; offset <= 3; offset += 1) {
23694
+ candidates.add(pairedBase + offset);
23695
+ }
23696
+ return [...candidates].sort((left, right) => left - right);
23697
+ }
23698
+ function parseNonNegativeIntegerToken(token) {
23699
+ if (token.length === 0) {
23700
+ return void 0;
23701
+ }
23702
+ let value = 0;
23703
+ for (const char of token) {
23704
+ const code = char.charCodeAt(0);
23705
+ if (code < 48 || code > 57) {
23706
+ return void 0;
23707
+ }
23708
+ value = value * 10 + (code - 48);
23709
+ }
23710
+ return value;
23711
+ }
23712
+ function normalizePositiveInteger2(value, fallback) {
23713
+ if (typeof value !== "number" || !Number.isFinite(value)) {
23714
+ return fallback;
23715
+ }
23716
+ return Math.max(0, Math.floor(value));
23717
+ }
23718
+ function isAsciiLetterOrDigit(char) {
23719
+ const code = char.charCodeAt(0);
23720
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
23721
+ }
23722
+ function isReferenceDash(char) {
23723
+ return char === "-" || char === "\u2010" || char === "\u2011" || char === "\u2012" || char === "\u2013" || char === "\u2014" || char === "\u2015";
23724
+ }
23725
+
23090
23726
  // ../remnic-core/src/recall-query-policy.ts
23091
23727
  var DEFAULT_STOPWORDS = /* @__PURE__ */ new Set([
23092
23728
  "the",
@@ -37930,6 +38566,27 @@ ${formatted}`;
37930
38566
  this.profiler.startSpan("assembly", profileTraceId);
37931
38567
  if (sharedCtx)
37932
38568
  this.appendRecallSection(sectionBuckets, "shared-context", sharedCtx);
38569
+ const explicitCueMaxChars = this.getRecallSectionMaxChars("explicit-cue") ?? this.config.explicitCueRecallMaxChars;
38570
+ if (this.config.explicitCueRecallEnabled && this.isRecallSectionEnabled("explicit-cue") && explicitCueMaxChars !== 0 && this.lcmEngine?.enabled && recallMode !== "no_recall") {
38571
+ try {
38572
+ const explicitCueSection = await buildExplicitCueRecallSection({
38573
+ engine: this.lcmEngine,
38574
+ sessionId: sessionKey,
38575
+ query: retrievalQuery,
38576
+ maxChars: explicitCueMaxChars,
38577
+ maxReferences: this.getRecallSectionNumber("explicit-cue", "maxResults") ?? this.config.explicitCueRecallMaxReferences
38578
+ });
38579
+ if (explicitCueSection) {
38580
+ this.appendRecallSection(
38581
+ sectionBuckets,
38582
+ "explicit-cue",
38583
+ explicitCueSection
38584
+ );
38585
+ }
38586
+ } catch (err) {
38587
+ log.debug(`Explicit cue recall assembly error: ${err}`);
38588
+ }
38589
+ }
37933
38590
  if (profile)
37934
38591
  this.appendRecallSection(
37935
38592
  sectionBuckets,
@@ -70914,8 +71571,7 @@ function buildTurnFingerprint(input) {
70914
71571
  // ../../src/index.ts
70915
71572
  import {
70916
71573
  resolvePrincipal as resolvePrincipal2,
70917
- resolveAgentAccessAuthToken as resolveAgentAccessAuthToken2,
70918
- hasEnabledLiveConnector as hasEnabledLiveConnector2
71574
+ resolveAgentAccessAuthToken as resolveAgentAccessAuthToken2
70919
71575
  } from "@remnic/core";
70920
71576
 
70921
71577
  // ../remnic-core/src/surfaces/dreams.ts
@@ -71494,6 +72150,17 @@ function liveConnectorCronExprForConfig(connectors) {
71494
72150
  return hasEnabledConnector ? ENABLED_LIVE_CONNECTOR_CRON_EXPR : DEFAULT_LIVE_CONNECTOR_CRON_EXPR;
71495
72151
  }
71496
72152
 
72153
+ // ../../src/openclaw-live-connector-config.ts
72154
+ function hasEnabledLiveConnectorConfig(config) {
72155
+ if (!config || typeof config !== "object" || Array.isArray(config)) return false;
72156
+ return Object.values(config).some((connector) => {
72157
+ if (!connector || typeof connector !== "object" || Array.isArray(connector)) {
72158
+ return false;
72159
+ }
72160
+ return connector.enabled === true;
72161
+ });
72162
+ }
72163
+
71497
72164
  // ../../src/index.ts
71498
72165
  var ENGRAM_MIGRATION_PROMISE = "__openclawEngramMigrationPromise";
71499
72166
  var CLI_REGISTERED_GUARD = "__openclawEngramCliRegistered";
@@ -71605,7 +72272,7 @@ function readPluginHooksPolicy(apiConfig, pluginId) {
71605
72272
  return loadPluginEntryFromFile(pluginId)?.["hooks"];
71606
72273
  }
71607
72274
  async function maybeRegisterLiveConnectorCron(orchestrator) {
71608
- if (!hasEnabledLiveConnector2(orchestrator.config.connectors)) return;
72275
+ if (!hasEnabledLiveConnectorConfig(orchestrator.config.connectors)) return;
71609
72276
  const jobsPath = path99.join(resolveHomeDir(), ".openclaw", "cron", "jobs.json");
71610
72277
  try {
71611
72278
  if (!existsSync12(jobsPath)) {
@@ -2192,6 +2192,23 @@
2192
2192
  "default": 300,
2193
2193
  "description": "Max tokens for each TMT summary node. Default: 300."
2194
2194
  },
2195
+ "explicitCueRecallEnabled": {
2196
+ "type": "boolean",
2197
+ "default": false,
2198
+ "description": "Front-load exact LCM evidence for query-visible cues such as turns, dates, ids, files, and tools."
2199
+ },
2200
+ "explicitCueRecallMaxChars": {
2201
+ "type": "number",
2202
+ "default": 2400,
2203
+ "minimum": 0,
2204
+ "description": "Character budget for the explicit cue evidence recall section."
2205
+ },
2206
+ "explicitCueRecallMaxReferences": {
2207
+ "type": "number",
2208
+ "default": 24,
2209
+ "minimum": 0,
2210
+ "description": "Maximum query-visible cues expanded by explicit cue recall."
2211
+ },
2195
2212
  "queryExpansionEnabled": {
2196
2213
  "type": "boolean",
2197
2214
  "default": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/plugin-openclaw",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "OpenClaw adapter for Remnic memory — thin wrapper delegating to @remnic/core",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",