@remnic/plugin-openclaw 1.0.9 → 1.0.11

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.
Files changed (69) hide show
  1. package/dist/{calibration-674TDQNV.js → calibration-WCHOK6DX.js} +12 -4
  2. package/dist/capsule-cli-TFKLAG3S.js +329 -0
  3. package/dist/capsule-crypto-K3IRTKRH.js +17 -0
  4. package/dist/capsule-export-CVA3CKUQ.js +265 -0
  5. package/dist/capsule-import-CFX7BY5W.js +16 -0
  6. package/dist/capsule-merge-7RVOHJK3.js +189 -0
  7. package/dist/{causal-chain-OKDZSDEB.js → causal-chain-WYN5QOPS.js} +3 -2
  8. package/dist/{causal-consolidation-5BEXLQV5.js → causal-consolidation-JD6KJJH6.js} +16 -12
  9. package/dist/{causal-retrieval-3BKBXVXD.js → causal-retrieval-NZHQOZOE.js} +6 -5
  10. package/dist/{causal-trajectory-graph-RQIT37DN.js → causal-trajectory-graph-VBPE2WPM.js} +1 -1
  11. package/dist/chunk-37NKFWSO.js +233 -0
  12. package/dist/chunk-3G7FAF6S.js +60 -0
  13. package/dist/{chunk-Z7GRLVK3.js → chunk-3GUF7RQI.js} +235 -19
  14. package/dist/chunk-3I7RHWYT.js +214 -0
  15. package/dist/chunk-4G2XCSD2.js +186 -0
  16. package/dist/chunk-6IWEAUN6.js +148 -0
  17. package/dist/{chunk-LN5UZQVG.js → chunk-6UFI73TJ.js} +5 -3
  18. package/dist/chunk-7OQEPGQF.js +529 -0
  19. package/dist/chunk-B52XADV3.js +244 -0
  20. package/dist/chunk-BU5KJVWF.js +78 -0
  21. package/dist/chunk-CXM7EBAO.js +289 -0
  22. package/dist/chunk-ETJZRIAM.js +227 -0
  23. package/dist/chunk-FQRSVYY4.js +110 -0
  24. package/dist/chunk-HRGFO6AW.js +349 -0
  25. package/dist/chunk-I6B2W2IY.js +47 -0
  26. package/dist/chunk-JZBOXOUC.js +259 -0
  27. package/dist/chunk-K7EUBNDD.js +185 -0
  28. package/dist/chunk-L4PRBB2A.js +1860 -0
  29. package/dist/chunk-MBIFE6SA.js +250 -0
  30. package/dist/chunk-N7EOZY6F.js +400 -0
  31. package/dist/chunk-NKVIN6RD.js +118 -0
  32. package/dist/chunk-OEI7GLV2.js +17 -0
  33. package/dist/{chunk-S2ISS4AH.js → chunk-P3DIW2SD.js} +10 -10
  34. package/dist/{chunk-7TENHBV2.js → chunk-RQCTMECT.js} +10 -48
  35. package/dist/chunk-SSFTU6LP.js +182 -0
  36. package/dist/{chunk-BXTMZDRT.js → chunk-SVSQAG6M.js} +7 -5
  37. package/dist/chunk-TLVIQLB4.js +874 -0
  38. package/dist/{chunk-JJSNPSCD.js → chunk-TNH24SF6.js} +352 -50
  39. package/dist/chunk-TVKKIS53.js +720 -0
  40. package/dist/{chunk-YHH3SXKD.js → chunk-WPINX4MF.js} +1 -59
  41. package/dist/{chunk-HCFFXBLV.js → chunk-XMSDA5WA.js} +5 -1861
  42. package/dist/chunk-YGGGUTG3.js +125 -0
  43. package/dist/chunk-YGXXBRV7.js +10 -0
  44. package/dist/cipher-VHAFCG7Z.js +27 -0
  45. package/dist/dreams-ledger-3I52ISYR.js +285 -0
  46. package/dist/{engine-65C2J63X.js → engine-VMTFKFGO.js} +5 -2
  47. package/dist/{fallback-llm-LVK5PDIM.js → fallback-llm-WCWNGIQ3.js} +2 -1
  48. package/dist/first-start-migration-I24M2JEE.js +258 -0
  49. package/dist/forget-NI4RBDPB.js +68 -0
  50. package/dist/fs-utils-PZRI2HDZ.js +29 -0
  51. package/dist/graph-edge-decay-5CVKWBYH.js +203 -0
  52. package/dist/index.js +9791 -2902
  53. package/dist/kdf-H5B23ZM2.js +25 -0
  54. package/dist/memory-governance-DWGFV4FX.js +25 -0
  55. package/dist/metadata-JAGIWHEA.js +20 -0
  56. package/dist/migrate-from-identity-anchor-N3354WMP.js +7 -0
  57. package/dist/path-5LCUBAAZ.js +8 -0
  58. package/dist/peers-JF2I6RCR.js +43 -0
  59. package/dist/purge-XN2VSPZ2.js +204 -0
  60. package/dist/secure-store-FWJ7LBPH.js +149 -0
  61. package/dist/state-PVISYXRH.js +7 -0
  62. package/dist/state-store-LP5BO6SF.js +15 -0
  63. package/dist/{storage-DM4ZGOCN.js → storage-T2OGFUF4.js} +3 -1
  64. package/dist/tier-stats-IZNW66NC.js +147 -0
  65. package/dist/trace-NJESSGH7.js +289 -0
  66. package/dist/tui-MGK2LYJY.js +12 -0
  67. package/dist/types-H5R5D3WF.js +30 -0
  68. package/openclaw.plugin.json +519 -4
  69. package/package.json +1 -1
@@ -0,0 +1,529 @@
1
+ import {
2
+ clamp01,
3
+ computeLifecycleValueInputs,
4
+ daysSince
5
+ } from "./chunk-4G2XCSD2.js";
6
+ import {
7
+ assertIsoRecordedAt,
8
+ assertSafePathSegment,
9
+ assertString,
10
+ isRecord,
11
+ optionalStringArray,
12
+ recordStoreDay,
13
+ validateStringRecord
14
+ } from "./chunk-3G7FAF6S.js";
15
+ import {
16
+ listJsonFiles,
17
+ readJsonFile
18
+ } from "./chunk-5LE4HTVL.js";
19
+
20
+ // ../remnic-core/src/tier-routing.ts
21
+ function computeTierValueScore(memory, now, signals) {
22
+ const fm = memory.frontmatter;
23
+ const inputs = computeLifecycleValueInputs(memory, now, signals);
24
+ const correctionBoost = fm.category === "correction" ? 0.08 : 0;
25
+ const confirmedBoost = fm.verificationState === "user_confirmed" ? 0.05 : 0;
26
+ const score = inputs.confidence * 0.24 + inputs.access * 0.26 + inputs.recency * 0.2 + inputs.importance * 0.2 + inputs.feedback * 0.1 + correctionBoost + confirmedBoost - inputs.disputedPenalty * 0.5;
27
+ return clamp01(score);
28
+ }
29
+ function decideTierTransition(memory, currentTier, policy, now, signals) {
30
+ const valueScore = computeTierValueScore(memory, now, signals);
31
+ if (!policy.enabled) {
32
+ return {
33
+ currentTier,
34
+ nextTier: currentTier,
35
+ valueScore,
36
+ changed: false,
37
+ reason: "tier_migration_disabled"
38
+ };
39
+ }
40
+ if (currentTier === "hot") {
41
+ const ageDays = daysSince(memory.frontmatter.updated ?? memory.frontmatter.created, now.getTime());
42
+ if (ageDays >= policy.demotionMinAgeDays && valueScore <= policy.demotionValueThreshold) {
43
+ return {
44
+ currentTier,
45
+ nextTier: "cold",
46
+ valueScore,
47
+ changed: true,
48
+ reason: "value_below_demotion_threshold"
49
+ };
50
+ }
51
+ return {
52
+ currentTier,
53
+ nextTier: currentTier,
54
+ valueScore,
55
+ changed: false,
56
+ reason: ageDays < policy.demotionMinAgeDays ? "demotion_min_age_not_met" : "value_above_demotion_threshold"
57
+ };
58
+ }
59
+ if (valueScore >= policy.promotionValueThreshold) {
60
+ return {
61
+ currentTier,
62
+ nextTier: "hot",
63
+ valueScore,
64
+ changed: true,
65
+ reason: "value_above_promotion_threshold"
66
+ };
67
+ }
68
+ return {
69
+ currentTier,
70
+ nextTier: currentTier,
71
+ valueScore,
72
+ changed: false,
73
+ reason: "value_below_promotion_threshold"
74
+ };
75
+ }
76
+
77
+ // ../remnic-core/src/utility-learner.ts
78
+ import path2 from "path";
79
+ import { mkdir as mkdir2, readFile, rename, writeFile as writeFile2 } from "fs/promises";
80
+
81
+ // ../remnic-core/src/utility-telemetry.ts
82
+ import path from "path";
83
+ import { mkdir, writeFile } from "fs/promises";
84
+ function resolveUtilityTelemetryDir(memoryDir, overrideDir) {
85
+ if (typeof overrideDir === "string" && overrideDir.trim().length > 0) {
86
+ return overrideDir.trim();
87
+ }
88
+ return path.join(memoryDir, "state", "utility-telemetry");
89
+ }
90
+ function assertUtilityScore(value) {
91
+ if (typeof value !== "number" || !Number.isFinite(value)) {
92
+ throw new Error("utilityScore must be a finite number");
93
+ }
94
+ if (value < -1 || value > 1) {
95
+ throw new Error("utilityScore must be between -1 and 1");
96
+ }
97
+ return value;
98
+ }
99
+ function validateUtilityTelemetryEvent(raw) {
100
+ if (!isRecord(raw)) throw new Error("utility telemetry event must be an object");
101
+ if (raw.schemaVersion !== 1) throw new Error("schemaVersion must be 1");
102
+ const source = assertString(raw.source, "source");
103
+ if (!["cli", "system", "benchmark", "tool_result"].includes(source)) {
104
+ throw new Error("source must be one of cli|system|benchmark|tool_result");
105
+ }
106
+ const target = assertString(raw.target, "target");
107
+ if (!["promotion", "ranking"].includes(target)) {
108
+ throw new Error("target must be one of promotion|ranking");
109
+ }
110
+ const decision = assertString(raw.decision, "decision");
111
+ if (!["promote", "demote", "hold", "boost", "suppress"].includes(decision)) {
112
+ throw new Error("decision must be one of promote|demote|hold|boost|suppress");
113
+ }
114
+ const outcome = assertString(raw.outcome, "outcome");
115
+ if (!["helpful", "neutral", "harmful"].includes(outcome)) {
116
+ throw new Error("outcome must be one of helpful|neutral|harmful");
117
+ }
118
+ return {
119
+ schemaVersion: 1,
120
+ eventId: assertSafePathSegment(assertString(raw.eventId, "eventId"), "eventId"),
121
+ recordedAt: assertIsoRecordedAt(assertString(raw.recordedAt, "recordedAt")),
122
+ sessionKey: assertString(raw.sessionKey, "sessionKey"),
123
+ source,
124
+ target,
125
+ decision,
126
+ outcome,
127
+ utilityScore: assertUtilityScore(raw.utilityScore),
128
+ summary: assertString(raw.summary, "summary"),
129
+ memoryIds: optionalStringArray(raw.memoryIds, "memoryIds"),
130
+ entityRefs: optionalStringArray(raw.entityRefs, "entityRefs"),
131
+ tags: optionalStringArray(raw.tags, "tags"),
132
+ metadata: validateStringRecord(raw.metadata, "metadata")
133
+ };
134
+ }
135
+ async function recordUtilityTelemetryEvent(options) {
136
+ const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
137
+ const validated = validateUtilityTelemetryEvent(options.event);
138
+ const day = recordStoreDay(validated.recordedAt);
139
+ const eventsDir = path.join(rootDir, "events", day);
140
+ const filePath = path.join(eventsDir, `${validated.eventId}.json`);
141
+ await mkdir(eventsDir, { recursive: true });
142
+ await writeFile(filePath, JSON.stringify(validated, null, 2), "utf8");
143
+ return filePath;
144
+ }
145
+ async function readUtilityTelemetryEvents(options) {
146
+ const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
147
+ const files = await listJsonFiles(path.join(rootDir, "events"));
148
+ const events = [];
149
+ const invalidEvents = [];
150
+ for (const filePath of files) {
151
+ try {
152
+ events.push(validateUtilityTelemetryEvent(await readJsonFile(filePath)));
153
+ } catch (error) {
154
+ invalidEvents.push({
155
+ path: filePath,
156
+ error: error instanceof Error ? error.message : String(error)
157
+ });
158
+ }
159
+ }
160
+ return { files, events, invalidEvents };
161
+ }
162
+ async function getUtilityTelemetryStatus(options) {
163
+ const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
164
+ const eventsDir = path.join(rootDir, "events");
165
+ if (!options.enabled) {
166
+ return {
167
+ enabled: false,
168
+ promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
169
+ rootDir,
170
+ eventsDir,
171
+ events: {
172
+ total: 0,
173
+ valid: 0,
174
+ invalid: 0,
175
+ byTarget: {},
176
+ byDecision: {},
177
+ byOutcome: {}
178
+ },
179
+ invalidEvents: []
180
+ };
181
+ }
182
+ const { files, events, invalidEvents } = await readUtilityTelemetryEvents(options);
183
+ events.sort((a, b) => b.recordedAt.localeCompare(a.recordedAt));
184
+ const byTarget = {};
185
+ const byDecision = {};
186
+ const byOutcome = {};
187
+ for (const event of events) {
188
+ byTarget[event.target] = (byTarget[event.target] ?? 0) + 1;
189
+ byDecision[event.decision] = (byDecision[event.decision] ?? 0) + 1;
190
+ byOutcome[event.outcome] = (byOutcome[event.outcome] ?? 0) + 1;
191
+ }
192
+ return {
193
+ enabled: true,
194
+ promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
195
+ rootDir,
196
+ eventsDir,
197
+ events: {
198
+ total: files.length,
199
+ valid: events.length,
200
+ invalid: invalidEvents.length,
201
+ byTarget,
202
+ byDecision,
203
+ byOutcome,
204
+ latestEventId: events[0]?.eventId,
205
+ latestRecordedAt: events[0]?.recordedAt,
206
+ latestSessionKey: events[0]?.sessionKey
207
+ },
208
+ latestEvent: events[0],
209
+ invalidEvents
210
+ };
211
+ }
212
+
213
+ // ../remnic-core/src/utility-learner.ts
214
+ var UTILITY_LEARNING_SNAPSHOT_VERSION = 1;
215
+ var UTILITY_LEARNING_STATE_FILE = "learning-state.json";
216
+ function clampWeight(value, maxWeightMagnitude) {
217
+ const limit = Number.isFinite(maxWeightMagnitude) && maxWeightMagnitude > 0 ? maxWeightMagnitude : 0;
218
+ return Math.max(-limit, Math.min(limit, value));
219
+ }
220
+ function coerceLearningWindowDays(value) {
221
+ if (!Number.isFinite(value)) return 14;
222
+ return Math.max(1, Math.floor(value));
223
+ }
224
+ function coerceMinEventCount(value) {
225
+ if (!Number.isFinite(value)) return 3;
226
+ return Math.max(1, Math.floor(value));
227
+ }
228
+ function coerceMaxWeightMagnitude(value) {
229
+ if (!Number.isFinite(value)) return 0.35;
230
+ return Math.max(0, Math.min(1, value));
231
+ }
232
+ function roundWeight(value) {
233
+ return Math.round(value * 1e3) / 1e3;
234
+ }
235
+ function outcomeCountsFor(events) {
236
+ const counts = {};
237
+ for (const event of events) {
238
+ counts[event.outcome] = (counts[event.outcome] ?? 0) + 1;
239
+ }
240
+ return counts;
241
+ }
242
+ function selectRecentEvents(events, now, windowDays) {
243
+ if (!Number.isFinite(windowDays) || windowDays <= 0) return [...events];
244
+ const minTimestamp = now.getTime() - windowDays * 864e5;
245
+ return events.filter((event) => {
246
+ const ts = Date.parse(event.recordedAt);
247
+ return Number.isFinite(ts) && ts >= minTimestamp;
248
+ });
249
+ }
250
+ function confidenceFromEvents(eventCount, averageUtilityScore) {
251
+ if (eventCount <= 0) return 0;
252
+ return roundWeight(clamp01(Math.abs(averageUtilityScore) * Math.min(1, eventCount / 10)));
253
+ }
254
+ function validateUtilityLearningSnapshot(raw) {
255
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
256
+ throw new Error("utility learning snapshot must be an object");
257
+ }
258
+ const record = raw;
259
+ if (record.version !== UTILITY_LEARNING_SNAPSHOT_VERSION) {
260
+ throw new Error("utility learning snapshot version must be 1");
261
+ }
262
+ if (typeof record.updatedAt !== "string" || record.updatedAt.length === 0) {
263
+ throw new Error("utility learning snapshot updatedAt must be a string");
264
+ }
265
+ if (typeof record.windowDays !== "number" || !Number.isFinite(record.windowDays) || record.windowDays < 0) {
266
+ throw new Error("utility learning snapshot windowDays must be a non-negative number");
267
+ }
268
+ if (typeof record.minEventCount !== "number" || !Number.isFinite(record.minEventCount) || record.minEventCount < 1) {
269
+ throw new Error("utility learning snapshot minEventCount must be >= 1");
270
+ }
271
+ if (typeof record.maxWeightMagnitude !== "number" || !Number.isFinite(record.maxWeightMagnitude) || record.maxWeightMagnitude < 0) {
272
+ throw new Error("utility learning snapshot maxWeightMagnitude must be >= 0");
273
+ }
274
+ if (!Array.isArray(record.weights)) {
275
+ throw new Error("utility learning snapshot weights must be an array");
276
+ }
277
+ const weights = record.weights.map((entry) => {
278
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
279
+ throw new Error("utility learning weight must be an object");
280
+ }
281
+ const weight = entry;
282
+ const target = weight.target;
283
+ const decision = weight.decision;
284
+ if (target !== "promotion" && target !== "ranking") {
285
+ throw new Error("utility learning weight target must be promotion|ranking");
286
+ }
287
+ if (!["promote", "demote", "hold", "boost", "suppress"].includes(String(decision))) {
288
+ throw new Error("utility learning weight decision is invalid");
289
+ }
290
+ if (typeof weight.eventCount !== "number" || !Number.isFinite(weight.eventCount) || weight.eventCount < 0) {
291
+ throw new Error("utility learning weight eventCount must be >= 0");
292
+ }
293
+ if (typeof weight.learnedWeight !== "number" || !Number.isFinite(weight.learnedWeight)) {
294
+ throw new Error("utility learning weight learnedWeight must be finite");
295
+ }
296
+ if (typeof weight.averageUtilityScore !== "number" || !Number.isFinite(weight.averageUtilityScore)) {
297
+ throw new Error("utility learning weight averageUtilityScore must be finite");
298
+ }
299
+ if (typeof weight.confidence !== "number" || !Number.isFinite(weight.confidence)) {
300
+ throw new Error("utility learning weight confidence must be finite");
301
+ }
302
+ if (typeof weight.updatedAt !== "string" || weight.updatedAt.length === 0) {
303
+ throw new Error("utility learning weight updatedAt must be a string");
304
+ }
305
+ const outcomeCounts = weight.outcomeCounts ?? {};
306
+ return {
307
+ target,
308
+ decision,
309
+ eventCount: weight.eventCount,
310
+ learnedWeight: roundWeight(weight.learnedWeight),
311
+ averageUtilityScore: roundWeight(weight.averageUtilityScore),
312
+ confidence: roundWeight(clamp01(weight.confidence)),
313
+ outcomeCounts,
314
+ updatedAt: weight.updatedAt
315
+ };
316
+ });
317
+ return {
318
+ version: 1,
319
+ updatedAt: record.updatedAt,
320
+ windowDays: record.windowDays,
321
+ minEventCount: record.minEventCount,
322
+ maxWeightMagnitude: record.maxWeightMagnitude,
323
+ weights
324
+ };
325
+ }
326
+ function resolveUtilityLearningStatePath(memoryDir, utilityTelemetryDir) {
327
+ return path2.join(resolveUtilityTelemetryDir(memoryDir, utilityTelemetryDir), UTILITY_LEARNING_STATE_FILE);
328
+ }
329
+ async function readUtilityLearningSnapshot(memoryDir, utilityTelemetryDir) {
330
+ const statePath = resolveUtilityLearningStatePath(memoryDir, utilityTelemetryDir);
331
+ try {
332
+ const raw = JSON.parse(await readFile(statePath, "utf8"));
333
+ return validateUtilityLearningSnapshot(raw);
334
+ } catch {
335
+ return null;
336
+ }
337
+ }
338
+ async function writeUtilityLearningSnapshot(statePath, snapshot) {
339
+ const tempPath = `${statePath}.tmp`;
340
+ await mkdir2(path2.dirname(statePath), { recursive: true });
341
+ await writeFile2(tempPath, `${JSON.stringify(snapshot, null, 2)}
342
+ `, "utf8");
343
+ await rename(tempPath, statePath);
344
+ }
345
+ async function learnUtilityPromotionWeights(options) {
346
+ const statePath = resolveUtilityLearningStatePath(options.memoryDir, options.utilityTelemetryDir);
347
+ if (!options.enabled) {
348
+ return {
349
+ applied: false,
350
+ reason: "disabled",
351
+ statePath,
352
+ snapshot: null
353
+ };
354
+ }
355
+ const now = options.now ?? /* @__PURE__ */ new Date();
356
+ const updatedAt = now.toISOString();
357
+ const windowDays = coerceLearningWindowDays(options.learningWindowDays);
358
+ const minEventCount = coerceMinEventCount(options.minEventCount);
359
+ const maxWeightMagnitude = coerceMaxWeightMagnitude(options.maxWeightMagnitude);
360
+ const recentEvents = selectRecentEvents(
361
+ (await readUtilityTelemetryEvents({
362
+ memoryDir: options.memoryDir,
363
+ utilityTelemetryDir: options.utilityTelemetryDir
364
+ })).events,
365
+ now,
366
+ windowDays
367
+ );
368
+ const grouped = /* @__PURE__ */ new Map();
369
+ for (const event of recentEvents) {
370
+ const key = `${event.target}:${event.decision}`;
371
+ const existing = grouped.get(key);
372
+ if (existing) {
373
+ existing.push(event);
374
+ } else {
375
+ grouped.set(key, [event]);
376
+ }
377
+ }
378
+ const weights = [];
379
+ for (const events of grouped.values()) {
380
+ if (events.length < minEventCount) continue;
381
+ const target = events[0].target;
382
+ const decision = events[0].decision;
383
+ const averageUtilityScore = events.reduce((sum, event) => sum + event.utilityScore, 0) / events.length;
384
+ const confidence = confidenceFromEvents(events.length, averageUtilityScore);
385
+ const learnedWeight = roundWeight(
386
+ clampWeight(averageUtilityScore * confidence, maxWeightMagnitude)
387
+ );
388
+ weights.push({
389
+ target,
390
+ decision,
391
+ eventCount: events.length,
392
+ learnedWeight,
393
+ averageUtilityScore: roundWeight(averageUtilityScore),
394
+ confidence,
395
+ outcomeCounts: outcomeCountsFor(events),
396
+ updatedAt
397
+ });
398
+ }
399
+ weights.sort((left, right) => {
400
+ const targetCompare = left.target.localeCompare(right.target);
401
+ if (targetCompare !== 0) return targetCompare;
402
+ return left.decision.localeCompare(right.decision);
403
+ });
404
+ const snapshot = {
405
+ version: 1,
406
+ updatedAt,
407
+ windowDays,
408
+ minEventCount,
409
+ maxWeightMagnitude,
410
+ weights
411
+ };
412
+ if (weights.length === 0) {
413
+ return {
414
+ applied: false,
415
+ reason: "insufficient_events",
416
+ statePath,
417
+ snapshot
418
+ };
419
+ }
420
+ await writeUtilityLearningSnapshot(statePath, snapshot);
421
+ return {
422
+ applied: true,
423
+ reason: "learned",
424
+ statePath,
425
+ snapshot
426
+ };
427
+ }
428
+ async function getUtilityLearningStatus(options) {
429
+ const rootDir = resolveUtilityTelemetryDir(options.memoryDir, options.utilityTelemetryDir);
430
+ const statePath = resolveUtilityLearningStatePath(options.memoryDir, options.utilityTelemetryDir);
431
+ if (!options.enabled) {
432
+ return {
433
+ enabled: false,
434
+ promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
435
+ rootDir,
436
+ statePath,
437
+ snapshot: null,
438
+ weights: {
439
+ total: 0,
440
+ positive: 0,
441
+ negative: 0,
442
+ zero: 0
443
+ }
444
+ };
445
+ }
446
+ const snapshot = await readUtilityLearningSnapshot(options.memoryDir, options.utilityTelemetryDir);
447
+ const weights = snapshot?.weights ?? [];
448
+ return {
449
+ enabled: true,
450
+ promotionByOutcomeEnabled: options.promotionByOutcomeEnabled === true,
451
+ rootDir,
452
+ statePath,
453
+ snapshot,
454
+ weights: {
455
+ total: weights.length,
456
+ positive: weights.filter((entry) => entry.learnedWeight > 0).length,
457
+ negative: weights.filter((entry) => entry.learnedWeight < 0).length,
458
+ zero: weights.filter((entry) => entry.learnedWeight === 0).length,
459
+ latestUpdatedAt: snapshot?.updatedAt
460
+ }
461
+ };
462
+ }
463
+
464
+ // ../remnic-core/src/utility-runtime.ts
465
+ var RANKING_MULTIPLIER_LIMIT = 0.12;
466
+ var PROMOTION_THRESHOLD_DELTA_LIMIT = 0.07;
467
+ var PROMOTION_THRESHOLD_WEIGHT_FACTOR = 0.2;
468
+ function roundRuntimeValue(value) {
469
+ return Math.round(value * 1e3) / 1e3;
470
+ }
471
+ function clampSigned(value, limit) {
472
+ if (!Number.isFinite(value) || limit <= 0) return 0;
473
+ return Math.max(-limit, Math.min(limit, value));
474
+ }
475
+ function learnedWeightFor(snapshot, target, decision) {
476
+ const entry = snapshot.weights.find((weight) => weight.target === target && weight.decision === decision);
477
+ return entry?.learnedWeight ?? 0;
478
+ }
479
+ async function loadUtilityRuntimeValues(options) {
480
+ if (!options.memoryUtilityLearningEnabled || !options.promotionByOutcomeEnabled) return null;
481
+ const snapshot = await readUtilityLearningSnapshot(options.memoryDir, options.utilityTelemetryDir);
482
+ if (!snapshot) return null;
483
+ return {
484
+ rankingBoostMultiplier: roundRuntimeValue(
485
+ 1 + clampSigned(learnedWeightFor(snapshot, "ranking", "boost"), RANKING_MULTIPLIER_LIMIT)
486
+ ),
487
+ rankingSuppressMultiplier: roundRuntimeValue(
488
+ 1 + clampSigned(learnedWeightFor(snapshot, "ranking", "suppress"), RANKING_MULTIPLIER_LIMIT)
489
+ ),
490
+ promoteThresholdDelta: roundRuntimeValue(
491
+ clampSigned(
492
+ learnedWeightFor(snapshot, "promotion", "promote") * -PROMOTION_THRESHOLD_WEIGHT_FACTOR,
493
+ PROMOTION_THRESHOLD_DELTA_LIMIT
494
+ )
495
+ ),
496
+ demoteThresholdDelta: roundRuntimeValue(
497
+ clampSigned(
498
+ learnedWeightFor(snapshot, "promotion", "demote") * PROMOTION_THRESHOLD_WEIGHT_FACTOR,
499
+ PROMOTION_THRESHOLD_DELTA_LIMIT
500
+ )
501
+ ),
502
+ snapshotUpdatedAt: snapshot.updatedAt
503
+ };
504
+ }
505
+ function applyUtilityRankingRuntimeDelta(delta, runtime, mode) {
506
+ if (!runtime || !Number.isFinite(delta) || delta === 0) return delta;
507
+ const multiplier = mode === "boost" ? runtime.rankingBoostMultiplier : runtime.rankingSuppressMultiplier;
508
+ return roundRuntimeValue(delta * multiplier);
509
+ }
510
+ function applyUtilityPromotionRuntimePolicy(policy, runtime) {
511
+ if (!runtime) return policy;
512
+ return {
513
+ ...policy,
514
+ demotionValueThreshold: roundRuntimeValue(clamp01(policy.demotionValueThreshold + runtime.demoteThresholdDelta)),
515
+ promotionValueThreshold: roundRuntimeValue(clamp01(policy.promotionValueThreshold + runtime.promoteThresholdDelta))
516
+ };
517
+ }
518
+
519
+ export {
520
+ computeTierValueScore,
521
+ decideTierTransition,
522
+ recordUtilityTelemetryEvent,
523
+ getUtilityTelemetryStatus,
524
+ learnUtilityPromotionWeights,
525
+ getUtilityLearningStatus,
526
+ loadUtilityRuntimeValues,
527
+ applyUtilityRankingRuntimeDelta,
528
+ applyUtilityPromotionRuntimePolicy
529
+ };