@agenr/openclaw-plugin 2026.6.2 → 2026.6.3
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.
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
parseExpiry,
|
|
29
29
|
parseRecallMode,
|
|
30
30
|
storeDurablesDetailed
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-U74RE3L7.js";
|
|
32
32
|
import {
|
|
33
33
|
containsAgenrMemoryContext,
|
|
34
34
|
createSessionStartRepository,
|
|
@@ -768,6 +768,17 @@ function buildSessionEndSourceRef(source) {
|
|
|
768
768
|
return `${SESSION_END_SOURCE_REF_PREFIX}${source.trim()}`;
|
|
769
769
|
}
|
|
770
770
|
|
|
771
|
+
// src/adapters/shared/light-dream-trigger-deps.ts
|
|
772
|
+
function buildLightDreamTriggerDeps(services) {
|
|
773
|
+
return {
|
|
774
|
+
port: services.dreaming,
|
|
775
|
+
dbPath: services.config.dbPath,
|
|
776
|
+
config: services.agenrConfig,
|
|
777
|
+
embedding: services.embedding,
|
|
778
|
+
...services.claimExtraction ? { createClaimExtractionLlm: () => services.claimExtraction.llm } : {}
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
771
782
|
// src/app/dreaming/background-triggers.ts
|
|
772
783
|
var MINUTE_MS = 60 * 1e3;
|
|
773
784
|
async function maybeRunLightDream(input, deps) {
|
|
@@ -852,6 +863,36 @@ function hasEvidence(scan) {
|
|
|
852
863
|
return scan.episodesSinceLastRun > 0 || scan.ingestFilesSinceLastRun > 0 || scan.durablesCreatedSinceLastRun > 0;
|
|
853
864
|
}
|
|
854
865
|
|
|
866
|
+
// src/adapters/shared/post-session-light-dream.ts
|
|
867
|
+
async function runPostSessionLightDream(params) {
|
|
868
|
+
const contextSuffix = params.sessionContext ? ` for ${params.sessionContext}` : "";
|
|
869
|
+
try {
|
|
870
|
+
const result = await maybeRunLightDream({ trigger: "post_session" }, params.deps);
|
|
871
|
+
if (result.status === "ran") {
|
|
872
|
+
params.logger.info(`[agenr] ${params.scope} light dream completed${contextSuffix} run=${result.result.runId}`);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (result.reason === "run_in_progress" || result.reason === "episode_write_in_progress") {
|
|
876
|
+
params.logger.info(`[agenr] ${params.scope} light dream skipped${contextSuffix} reason=${result.reason}`);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
params.logger.debug?.(`[agenr] ${params.scope} light dream skipped${contextSuffix} reason=${result.reason}`);
|
|
880
|
+
} catch (error) {
|
|
881
|
+
params.logger.warn(`[agenr] ${params.scope} light dream failed${contextSuffix}: ${formatErrorMessage(error)}`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/adapters/shared/guarded-post-session-episode-capture.ts
|
|
886
|
+
async function runGuardedPostSessionEpisodeCapture(params) {
|
|
887
|
+
await withEpisodeWriteGuard({ port: params.services.dreaming, dbPath: params.services.config.dbPath }, params.writeEpisode);
|
|
888
|
+
await runPostSessionLightDream({
|
|
889
|
+
deps: buildLightDreamTriggerDeps(params.services),
|
|
890
|
+
logger: params.logger,
|
|
891
|
+
scope: params.scope,
|
|
892
|
+
sessionContext: params.sessionContext
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
|
|
855
896
|
// src/adapters/plugin-runtime/claim-extraction.ts
|
|
856
897
|
async function buildClaimExtractionRuntime(config, resolveLlm) {
|
|
857
898
|
const claimExtractionConfig = resolveClaimExtractionConfig(config);
|
|
@@ -2042,6 +2083,12 @@ async function createHostMemoryServices(featureFlags, options = {}) {
|
|
|
2042
2083
|
};
|
|
2043
2084
|
}
|
|
2044
2085
|
|
|
2086
|
+
// src/adapters/shared/shutdown-episode-threshold.ts
|
|
2087
|
+
var HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD = {
|
|
2088
|
+
minMaterialTurns: 8,
|
|
2089
|
+
minDurationMs: 20 * 60 * 1e3
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2045
2092
|
// src/adapters/shared/bounded-episode-embedding.ts
|
|
2046
2093
|
var EPISODE_EMBEDDING_RACE_TIMEOUT = /* @__PURE__ */ Symbol("episode-embedding-race-timeout");
|
|
2047
2094
|
var EPISODE_EMBEDDING_MIN_HEADROOM_MS = 5e3;
|
|
@@ -2982,6 +3029,7 @@ export {
|
|
|
2982
3029
|
isPluginEpisodeWriteEnabled,
|
|
2983
3030
|
resolveAgenrFeatureFlags,
|
|
2984
3031
|
resolveCompactionPromptContext,
|
|
3032
|
+
HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD,
|
|
2985
3033
|
embedEpisodeSummaryWithinBudget,
|
|
2986
3034
|
EPISODE_SUMMARY_TIMEOUT_MS,
|
|
2987
3035
|
writeBoundedSingleTranscriptEpisode,
|
|
@@ -2989,7 +3037,9 @@ export {
|
|
|
2989
3037
|
buildSessionFileSourceRef,
|
|
2990
3038
|
buildCompactionSourceRef,
|
|
2991
3039
|
buildSessionEndSourceRef,
|
|
3040
|
+
buildLightDreamTriggerDeps,
|
|
2992
3041
|
maybeRunLightDream,
|
|
3042
|
+
runGuardedPostSessionEpisodeCapture,
|
|
2993
3043
|
buildClaimExtractionRuntime,
|
|
2994
3044
|
createClaimExtractionFromAgenrConfig,
|
|
2995
3045
|
createEmbedQuery,
|
|
@@ -343,64 +343,6 @@ function sanitizeFetchToolParams(params) {
|
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
// src/app/episode-ingest/activity-threshold.ts
|
|
347
|
-
function resolveEpisodeActivityEligibility(materialTurns, startedAt, endedAt, threshold) {
|
|
348
|
-
const durationMs = resolveTranscriptDurationMs(startedAt, endedAt);
|
|
349
|
-
if (materialTurns >= threshold.minMaterialTurns || durationMs >= threshold.minDurationMs) {
|
|
350
|
-
return {
|
|
351
|
-
eligible: true,
|
|
352
|
-
materialTurns,
|
|
353
|
-
durationMs
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
return {
|
|
357
|
-
eligible: false,
|
|
358
|
-
reason: "below_activity_threshold",
|
|
359
|
-
materialTurns,
|
|
360
|
-
durationMs
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
function resolveTranscriptDurationMs(startedAt, endedAt) {
|
|
364
|
-
if (!startedAt || !endedAt) {
|
|
365
|
-
return 0;
|
|
366
|
-
}
|
|
367
|
-
const started = Date.parse(startedAt);
|
|
368
|
-
const ended = Date.parse(endedAt);
|
|
369
|
-
return Number.isFinite(started) && Number.isFinite(ended) && ended > started ? ended - started : 0;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// src/core/episode/transcript-render.ts
|
|
373
|
-
var MIN_EPISODE_MESSAGES = 4;
|
|
374
|
-
var MAX_EPISODE_TRANSCRIPT_CHARS = 14e3;
|
|
375
|
-
function countMaterialTranscriptTurns(messages) {
|
|
376
|
-
return messages.filter((message) => message.text.trim().length > 0).length;
|
|
377
|
-
}
|
|
378
|
-
function renderTranscript(messages) {
|
|
379
|
-
return messages.map((message) => `${message.role === "user" ? "User" : "Assistant"}: ${message.text.trim()}`).join("\n");
|
|
380
|
-
}
|
|
381
|
-
function capEpisodeTranscript(transcript, maxChars) {
|
|
382
|
-
if (transcript.length <= maxChars) {
|
|
383
|
-
return transcript;
|
|
384
|
-
}
|
|
385
|
-
const omissionMarker = "\n\n[Earlier middle transcript omitted for brevity]\n\n";
|
|
386
|
-
const headBudget = Math.max(0, Math.floor((maxChars - omissionMarker.length) * 0.35));
|
|
387
|
-
const tailBudget = Math.max(0, maxChars - omissionMarker.length - headBudget);
|
|
388
|
-
const head = trimToBoundary(transcript.slice(0, headBudget), false);
|
|
389
|
-
const tail = trimToBoundary(transcript.slice(-tailBudget), true);
|
|
390
|
-
return `${head}${omissionMarker}${tail}`.trim();
|
|
391
|
-
}
|
|
392
|
-
function trimToBoundary(value, fromStart) {
|
|
393
|
-
if (value.length === 0) {
|
|
394
|
-
return value;
|
|
395
|
-
}
|
|
396
|
-
if (fromStart) {
|
|
397
|
-
const boundary = value.search(/\s/u);
|
|
398
|
-
return boundary >= 0 ? value.slice(boundary).trimStart() : value.trim();
|
|
399
|
-
}
|
|
400
|
-
const reversedBoundary = value.trimEnd().search(/\s\S*$/u);
|
|
401
|
-
return reversedBoundary >= 0 ? value.slice(0, reversedBoundary).trimEnd() : value.trim();
|
|
402
|
-
}
|
|
403
|
-
|
|
404
346
|
// src/app/episode-ingest/single-transcript.ts
|
|
405
347
|
function createSingleTranscriptDiscoveryPort(filePath) {
|
|
406
348
|
return {
|
|
@@ -693,6 +635,66 @@ async function generateEpisodeSummary(transcript, llm) {
|
|
|
693
635
|
|
|
694
636
|
// src/app/episode-ingest/service/preflight.ts
|
|
695
637
|
import path from "path";
|
|
638
|
+
|
|
639
|
+
// src/app/episode-ingest/activity-threshold.ts
|
|
640
|
+
function resolveEpisodeActivityEligibility(materialTurns, startedAt, endedAt, threshold) {
|
|
641
|
+
const durationMs = resolveTranscriptDurationMs(startedAt, endedAt);
|
|
642
|
+
if (materialTurns >= threshold.minMaterialTurns || durationMs >= threshold.minDurationMs) {
|
|
643
|
+
return {
|
|
644
|
+
eligible: true,
|
|
645
|
+
materialTurns,
|
|
646
|
+
durationMs
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
eligible: false,
|
|
651
|
+
reason: "below_activity_threshold",
|
|
652
|
+
materialTurns,
|
|
653
|
+
durationMs
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function resolveTranscriptDurationMs(startedAt, endedAt) {
|
|
657
|
+
if (!startedAt || !endedAt) {
|
|
658
|
+
return 0;
|
|
659
|
+
}
|
|
660
|
+
const started = Date.parse(startedAt);
|
|
661
|
+
const ended = Date.parse(endedAt);
|
|
662
|
+
return Number.isFinite(started) && Number.isFinite(ended) && ended > started ? ended - started : 0;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/core/episode/transcript-render.ts
|
|
666
|
+
var MIN_EPISODE_MESSAGES = 4;
|
|
667
|
+
var MAX_EPISODE_TRANSCRIPT_CHARS = 14e3;
|
|
668
|
+
function countMaterialTranscriptTurns(messages) {
|
|
669
|
+
return messages.filter((message) => message.text.trim().length > 0).length;
|
|
670
|
+
}
|
|
671
|
+
function renderTranscript(messages) {
|
|
672
|
+
return messages.map((message) => `${message.role === "user" ? "User" : "Assistant"}: ${message.text.trim()}`).join("\n");
|
|
673
|
+
}
|
|
674
|
+
function capEpisodeTranscript(transcript, maxChars) {
|
|
675
|
+
if (transcript.length <= maxChars) {
|
|
676
|
+
return transcript;
|
|
677
|
+
}
|
|
678
|
+
const omissionMarker = "\n\n[Earlier middle transcript omitted for brevity]\n\n";
|
|
679
|
+
const headBudget = Math.max(0, Math.floor((maxChars - omissionMarker.length) * 0.35));
|
|
680
|
+
const tailBudget = Math.max(0, maxChars - omissionMarker.length - headBudget);
|
|
681
|
+
const head = trimToBoundary(transcript.slice(0, headBudget), false);
|
|
682
|
+
const tail = trimToBoundary(transcript.slice(-tailBudget), true);
|
|
683
|
+
return `${head}${omissionMarker}${tail}`.trim();
|
|
684
|
+
}
|
|
685
|
+
function trimToBoundary(value, fromStart) {
|
|
686
|
+
if (value.length === 0) {
|
|
687
|
+
return value;
|
|
688
|
+
}
|
|
689
|
+
if (fromStart) {
|
|
690
|
+
const boundary = value.search(/\s/u);
|
|
691
|
+
return boundary >= 0 ? value.slice(boundary).trimStart() : value.trim();
|
|
692
|
+
}
|
|
693
|
+
const reversedBoundary = value.trimEnd().search(/\s\S*$/u);
|
|
694
|
+
return reversedBoundary >= 0 ? value.slice(0, reversedBoundary).trimEnd() : value.trim();
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/app/episode-ingest/service/preflight.ts
|
|
696
698
|
var ACTIVE_SESSION_WINDOW_MS = 5 * 60 * 1e3;
|
|
697
699
|
async function prepareEpisodeIngest(targetPath, ports, options = {}) {
|
|
698
700
|
const files = await ports.files.discoverFiles(targetPath);
|
package/dist/index.js
CHANGED
|
@@ -6,15 +6,17 @@ import {
|
|
|
6
6
|
openClawTranscriptParser,
|
|
7
7
|
parseJsonObjectLineWithDiagnostics,
|
|
8
8
|
parseTuiSessionKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-IBPS64W3.js";
|
|
10
10
|
import {
|
|
11
11
|
EPISODE_SUMMARY_TIMEOUT_MS,
|
|
12
12
|
FETCH_TOOL_PARAMETERS,
|
|
13
|
+
HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD,
|
|
13
14
|
RECALL_TOOL_PARAMETERS,
|
|
14
15
|
STORE_TOOL_PARAMETERS,
|
|
15
16
|
UPDATE_TOOL_PARAMETERS,
|
|
16
17
|
buildClaimExtractionRuntime,
|
|
17
18
|
buildCompactionSourceRef,
|
|
19
|
+
buildLightDreamTriggerDeps,
|
|
18
20
|
buildRecallToolServices,
|
|
19
21
|
buildSessionEndSourceRef,
|
|
20
22
|
buildSessionFileSourceRef,
|
|
@@ -48,12 +50,13 @@ import {
|
|
|
48
50
|
resolveSessionStartPolicy,
|
|
49
51
|
routeSessionMemoryTriggerSafely,
|
|
50
52
|
runFetchMemoryTool,
|
|
53
|
+
runGuardedPostSessionEpisodeCapture,
|
|
51
54
|
runRecallMemoryTool,
|
|
52
55
|
runStoreMemoryTool,
|
|
53
56
|
runUpdateMemoryTool,
|
|
54
57
|
scheduleGuardedEpisodeWrite,
|
|
55
58
|
writeBoundedSingleTranscriptEpisode
|
|
56
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-SIY3JA7T.js";
|
|
57
60
|
import "./chunk-OJSIZDZD.js";
|
|
58
61
|
import "./chunk-NSLTJBUC.js";
|
|
59
62
|
import {
|
|
@@ -68,7 +71,7 @@ import {
|
|
|
68
71
|
formatTargetSelector,
|
|
69
72
|
sanitizeFetchToolParams,
|
|
70
73
|
sanitizeUpdateToolParams
|
|
71
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-U74RE3L7.js";
|
|
72
75
|
import {
|
|
73
76
|
formatAgenrBeforeTurnRecall,
|
|
74
77
|
runBeforeTurn,
|
|
@@ -84,9 +87,7 @@ import {
|
|
|
84
87
|
sanitizeStoreToolParams
|
|
85
88
|
} from "./chunk-5TIP2EPP.js";
|
|
86
89
|
import "./chunk-GAERET5Q.js";
|
|
87
|
-
import
|
|
88
|
-
withEpisodeWriteGuard
|
|
89
|
-
} from "./chunk-SOQW7356.js";
|
|
90
|
+
import "./chunk-SOQW7356.js";
|
|
90
91
|
import "./chunk-VTHBPXDQ.js";
|
|
91
92
|
import "./chunk-VBPYU7GO.js";
|
|
92
93
|
|
|
@@ -294,7 +295,7 @@ function createAgenrStoreTool(ctx, servicesPromise, logger) {
|
|
|
294
295
|
session: ctx,
|
|
295
296
|
sourcePrefix: "openclaw-session",
|
|
296
297
|
defaultSourceContext: "Stored via agenr_store from OpenClaw.",
|
|
297
|
-
onWarning: (warning) => logger.
|
|
298
|
+
onWarning: (warning) => logger.info(`[agenr] tool=agenr_store session=${ctx.sessionId ?? "unknown"} note: ${warning}`)
|
|
298
299
|
});
|
|
299
300
|
triggerOpenClawImportanceLightDream(services, logger, outcome.details.status);
|
|
300
301
|
return toOpenClawToolResult(outcome);
|
|
@@ -309,16 +310,7 @@ function triggerOpenClawImportanceLightDream(services, logger, status) {
|
|
|
309
310
|
if (status !== "stored") {
|
|
310
311
|
return;
|
|
311
312
|
}
|
|
312
|
-
void maybeRunLightDream(
|
|
313
|
-
{ trigger: "importance" },
|
|
314
|
-
{
|
|
315
|
-
port: services.dreaming,
|
|
316
|
-
dbPath: services.config.dbPath,
|
|
317
|
-
config: services.agenrConfig,
|
|
318
|
-
embedding: services.embedding,
|
|
319
|
-
...services.claimExtraction ? { createClaimExtractionLlm: () => services.claimExtraction.llm } : {}
|
|
320
|
-
}
|
|
321
|
-
).then((result) => {
|
|
313
|
+
void maybeRunLightDream({ trigger: "importance" }, buildLightDreamTriggerDeps(services)).then((result) => {
|
|
322
314
|
if (result.status === "ran") {
|
|
323
315
|
logger.info(`[agenr] importance light dream completed run=${result.result.runId}`);
|
|
324
316
|
} else if (result.reason === "run_in_progress" || result.reason === "episode_write_in_progress") {
|
|
@@ -385,7 +377,7 @@ function registerAgenrOpenClawTools(api, servicesPromise, logger) {
|
|
|
385
377
|
var openclaw_plugin_default = {
|
|
386
378
|
id: "agenr",
|
|
387
379
|
name: "agenr",
|
|
388
|
-
version: "2026.6.
|
|
380
|
+
version: "2026.6.3",
|
|
389
381
|
description: "agenr memory plugin for OpenClaw",
|
|
390
382
|
kind: "memory",
|
|
391
383
|
contracts: {
|
|
@@ -1133,17 +1125,18 @@ function normalizeOptionalString(value) {
|
|
|
1133
1125
|
var OPENCLAW_EPISODE_GENERATOR_VERSION = "openclaw-episodic-summary-v1";
|
|
1134
1126
|
|
|
1135
1127
|
// src/adapters/openclaw/episode/episode-writer.ts
|
|
1136
|
-
async function
|
|
1128
|
+
async function writeOpenClawSessionEndEpisode(params) {
|
|
1137
1129
|
await writeOpenClawSessionEpisode({
|
|
1138
1130
|
ctx: params.ctx,
|
|
1139
|
-
target: params.
|
|
1131
|
+
target: params.target,
|
|
1140
1132
|
services: params.services,
|
|
1141
1133
|
logger: params.logger,
|
|
1142
1134
|
actionLabel: "session-end episode write",
|
|
1143
|
-
sourceSessionId: params.
|
|
1135
|
+
sourceSessionId: params.target.sessionId,
|
|
1144
1136
|
fileField: "file",
|
|
1145
1137
|
shortCountField: "materialTurns",
|
|
1146
|
-
|
|
1138
|
+
activityGate: "host-shutdown",
|
|
1139
|
+
embeddingSkipLogContext: `[agenr] session-end episode embedding skipped for ${formatSessionContext(params.ctx.sessionId, params.ctx.sessionKey)} file=${params.target.sessionFile}`
|
|
1147
1140
|
});
|
|
1148
1141
|
}
|
|
1149
1142
|
async function writeOpenClawPreCompactionEpisode(params) {
|
|
@@ -1159,6 +1152,7 @@ async function writeOpenClawPreCompactionEpisode(params) {
|
|
|
1159
1152
|
sourceSessionId: `${params.sessionId}:pre-compaction:${params.messageCount}`,
|
|
1160
1153
|
fileField: "file",
|
|
1161
1154
|
shortCountField: "materialTurns",
|
|
1155
|
+
activityGate: "none",
|
|
1162
1156
|
embeddingSkipLogContext: `[agenr] pre-compaction episode embedding skipped for ${formatSessionContext(params.ctx.sessionId, params.ctx.sessionKey)} file=${params.sessionFile}`
|
|
1163
1157
|
});
|
|
1164
1158
|
}
|
|
@@ -1223,6 +1217,7 @@ async function writeOpenClawSessionEpisode(params) {
|
|
|
1223
1217
|
ingestOptions: {
|
|
1224
1218
|
genVersion: OPENCLAW_EPISODE_GENERATOR_VERSION,
|
|
1225
1219
|
skipActiveSessionCheck: true,
|
|
1220
|
+
...params.activityGate === "host-shutdown" ? { activityThreshold: HOST_SHUTDOWN_EPISODE_ACTIVITY_THRESHOLD } : {},
|
|
1226
1221
|
candidateOverrides: {
|
|
1227
1222
|
sessionId: params.sourceSessionId,
|
|
1228
1223
|
agentId: trimOptionalString(params.ctx.agentId) ?? null,
|
|
@@ -1415,9 +1410,6 @@ function buildOpenClawSessionShutdownTriggerEvent(scope, event) {
|
|
|
1415
1410
|
function shouldRouteOpenClawSessionTreeTrigger(reason) {
|
|
1416
1411
|
return reason !== void 0 && TREE_SESSION_END_REASONS.has(reason);
|
|
1417
1412
|
}
|
|
1418
|
-
function shouldSkipOpenClawSessionEndMemoryTrigger(reason) {
|
|
1419
|
-
return reason === "compaction";
|
|
1420
|
-
}
|
|
1421
1413
|
function buildOpenClawCompactionCheckpointArtifact(sessionKey, event, compactionEntry) {
|
|
1422
1414
|
const sourceId = compactionEntry?.id?.trim() || event.sessionFile?.trim() || `${sessionKey}:${event.compactedCount}`;
|
|
1423
1415
|
const summary = compactionEntry?.summary.trim() || `Compacted ${event.compactedCount} messages; ${event.messageCount} messages remain.`;
|
|
@@ -1848,32 +1840,25 @@ function resolveAgentIdFromSessionKey(sessionKey) {
|
|
|
1848
1840
|
return match?.[1]?.trim() || void 0;
|
|
1849
1841
|
}
|
|
1850
1842
|
|
|
1851
|
-
// src/adapters/openclaw/
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
const
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
...event.sessionKey ? { sessionKey: event.sessionKey } : {}
|
|
1858
|
-
};
|
|
1859
|
-
if (!shouldSkipOpenClawSessionEndMemoryTrigger(event.reason)) {
|
|
1860
|
-
if (shouldRouteOpenClawSessionTreeTrigger(event.reason)) {
|
|
1861
|
-
await routeOpenClawSessionMemoryTrigger(params.servicesPromise, scopeContext, (scope) => buildOpenClawSessionTreeTriggerEvent(scope, event));
|
|
1862
|
-
} else {
|
|
1863
|
-
await routeOpenClawSessionMemoryTrigger(params.servicesPromise, scopeContext, (scope) => buildOpenClawSessionShutdownTriggerEvent(scope, event));
|
|
1864
|
-
}
|
|
1843
|
+
// src/adapters/openclaw/episode/session-end-episode-write.ts
|
|
1844
|
+
function resolveOpenClawSessionEndEpisodeTarget(event) {
|
|
1845
|
+
const sessionId = event.sessionId.trim();
|
|
1846
|
+
const sessionFile = event.sessionFile?.trim();
|
|
1847
|
+
if (!sessionId || !sessionFile) {
|
|
1848
|
+
return void 0;
|
|
1865
1849
|
}
|
|
1850
|
+
return { sessionId, sessionFile };
|
|
1851
|
+
}
|
|
1852
|
+
async function runOpenClawSessionEndEpisodeCapture(params) {
|
|
1853
|
+
const sessionContext = formatSessionContext(params.event.sessionId, params.event.sessionKey);
|
|
1854
|
+
const syncTarget = resolveOpenClawSessionEndEpisodeTarget(params.event);
|
|
1866
1855
|
try {
|
|
1867
1856
|
const services = await params.servicesPromise;
|
|
1868
1857
|
if (!isPluginEpisodeWriteEnabled(services.pluginConfig.memoryPolicy)) {
|
|
1869
1858
|
params.logger.debug?.(`[agenr] session-end episode write skipped for ${sessionContext} reason=memory_policy_disabled`);
|
|
1870
1859
|
return;
|
|
1871
1860
|
}
|
|
1872
|
-
const
|
|
1873
|
-
sessionId: event.sessionId,
|
|
1874
|
-
...event.sessionKey ? { sessionKey: event.sessionKey } : {}
|
|
1875
|
-
};
|
|
1876
|
-
const target = await resolveOpenClawCurrentSessionTarget(ctx, {
|
|
1861
|
+
const target = syncTarget ?? await resolveOpenClawCurrentSessionTarget(params.ctx, {
|
|
1877
1862
|
resolveStateDir: services.openClaw.runtime.state.resolveStateDir,
|
|
1878
1863
|
logger: params.logger
|
|
1879
1864
|
});
|
|
@@ -1881,37 +1866,60 @@ async function handleAgenrSessionEnd(event, params) {
|
|
|
1881
1866
|
params.logger.info(`[agenr] session-end episode write skipped for ${sessionContext} reason=no_current_session`);
|
|
1882
1867
|
return;
|
|
1883
1868
|
}
|
|
1884
|
-
await
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1869
|
+
await runGuardedPostSessionEpisodeCapture({
|
|
1870
|
+
services,
|
|
1871
|
+
writeEpisode: () => writeOpenClawSessionEndEpisode({
|
|
1872
|
+
ctx: params.ctx,
|
|
1873
|
+
target,
|
|
1874
|
+
services,
|
|
1875
|
+
logger: params.logger
|
|
1876
|
+
}),
|
|
1877
|
+
logger: params.logger,
|
|
1878
|
+
scope: "session-end",
|
|
1879
|
+
sessionContext
|
|
1880
|
+
});
|
|
1889
1881
|
} catch (error) {
|
|
1890
|
-
params.logger.warn(`[agenr] session-end episode write failed for ${sessionContext}: ${
|
|
1882
|
+
params.logger.warn(`[agenr] session-end episode write failed for ${sessionContext}: ${formatErrorMessage(error)}`);
|
|
1891
1883
|
}
|
|
1892
1884
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1885
|
+
|
|
1886
|
+
// src/adapters/openclaw/session-end-policy.ts
|
|
1887
|
+
function resolveOpenClawSessionEndPolicy(reason) {
|
|
1888
|
+
const isCompaction = reason === "compaction";
|
|
1889
|
+
return {
|
|
1890
|
+
routeMemoryIntake: !isCompaction,
|
|
1891
|
+
captureEpisode: !isCompaction
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// src/adapters/openclaw/hooks/session-end.ts
|
|
1896
|
+
async function handleAgenrSessionEnd(event, params) {
|
|
1897
|
+
params.midSessionTracker.clear(event.sessionId, event.sessionKey);
|
|
1898
|
+
const scopeContext = {
|
|
1899
|
+
sessionId: event.sessionId,
|
|
1900
|
+
...event.sessionKey ? { sessionKey: event.sessionKey } : {}
|
|
1901
|
+
};
|
|
1902
|
+
const policy = resolveOpenClawSessionEndPolicy(event.reason);
|
|
1903
|
+
if (policy.routeMemoryIntake) {
|
|
1904
|
+
if (shouldRouteOpenClawSessionTreeTrigger(event.reason)) {
|
|
1905
|
+
await routeOpenClawSessionMemoryTrigger(params.servicesPromise, scopeContext, (scope) => buildOpenClawSessionTreeTriggerEvent(scope, event));
|
|
1909
1906
|
} else {
|
|
1910
|
-
|
|
1907
|
+
await routeOpenClawSessionMemoryTrigger(params.servicesPromise, scopeContext, (scope) => buildOpenClawSessionShutdownTriggerEvent(scope, event));
|
|
1911
1908
|
}
|
|
1912
|
-
} catch (error) {
|
|
1913
|
-
logger.warn(`[agenr] session-end light dream failed for ${sessionContext}: ${formatErrorMessage2(error)}`);
|
|
1914
1909
|
}
|
|
1910
|
+
if (!policy.captureEpisode) {
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
const ctx = {
|
|
1914
|
+
sessionId: event.sessionId,
|
|
1915
|
+
...event.sessionKey ? { sessionKey: event.sessionKey } : {}
|
|
1916
|
+
};
|
|
1917
|
+
await runOpenClawSessionEndEpisodeCapture({
|
|
1918
|
+
event,
|
|
1919
|
+
ctx,
|
|
1920
|
+
servicesPromise: params.servicesPromise,
|
|
1921
|
+
logger: params.logger
|
|
1922
|
+
});
|
|
1915
1923
|
}
|
|
1916
1924
|
|
|
1917
1925
|
// src/adapters/openclaw/memory/flush-plan.ts
|
package/openclaw.plugin.json
CHANGED