nexus-agents 2.28.0 → 2.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -10
- package/dist/chunk-5VZLXMO7.js +838 -0
- package/dist/chunk-5VZLXMO7.js.map +1 -0
- package/dist/chunk-633WH2ML.js +127 -0
- package/dist/chunk-633WH2ML.js.map +1 -0
- package/dist/chunk-7F6HYUIY.js +327 -0
- package/dist/chunk-7F6HYUIY.js.map +1 -0
- package/dist/chunk-CLYZ7FWP.js +30 -0
- package/dist/chunk-CLYZ7FWP.js.map +1 -0
- package/dist/{chunk-QZEAD6AG.js → chunk-DAMRMAM2.js} +19526 -35943
- package/dist/chunk-DAMRMAM2.js.map +1 -0
- package/dist/{chunk-YSDUVCCZ.js → chunk-HH5LVGEE.js} +6 -6
- package/dist/{chunk-E7EX2KQJ.js → chunk-HWDBNDUX.js} +2 -2
- package/dist/chunk-I6YDS23R.js +354 -0
- package/dist/chunk-I6YDS23R.js.map +1 -0
- package/dist/{chunk-L2SHSW4T.js → chunk-IMWYKX4H.js} +4377 -4190
- package/dist/chunk-IMWYKX4H.js.map +1 -0
- package/dist/chunk-KGDG6PWZ.js +61 -0
- package/dist/chunk-KGDG6PWZ.js.map +1 -0
- package/dist/chunk-POBO4G2P.js +3700 -0
- package/dist/chunk-POBO4G2P.js.map +1 -0
- package/dist/chunk-S3BKWNST.js +13475 -0
- package/dist/chunk-S3BKWNST.js.map +1 -0
- package/dist/chunk-T7PU3NPQ.js +42 -0
- package/dist/chunk-T7PU3NPQ.js.map +1 -0
- package/dist/{chunk-UGNLR4NZ.js → chunk-WSK4VSXP.js} +2 -2
- package/dist/{chunk-LKSTILEE.js → chunk-ZBZJHXRT.js} +181 -1120
- package/dist/chunk-ZBZJHXRT.js.map +1 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +1400 -649
- package/dist/cli.js.map +1 -1
- package/dist/composite-router-YPRWVTRB.js +17 -0
- package/dist/consensus-vote-DBE6RNZG.js +23 -0
- package/dist/{dist-H5XNXVAV.js → dist-7PQR2BQB.js} +1006 -954
- package/dist/dist-7PQR2BQB.js.map +1 -0
- package/dist/{doctor-deep-BDE2PHVX.js → doctor-deep-AWE7SRU6.js} +4 -3
- package/dist/expert-config-FHNBQRX2.js +22 -0
- package/dist/expert-config-FHNBQRX2.js.map +1 -0
- package/dist/factory-O5C7ZBZO.js +13 -0
- package/dist/factory-O5C7ZBZO.js.map +1 -0
- package/dist/factory-PCHGQ3ZG.js +16 -0
- package/dist/factory-PCHGQ3ZG.js.map +1 -0
- package/dist/index.d.ts +1253 -681
- package/dist/index.js +490 -313
- package/dist/index.js.map +1 -1
- package/dist/learning-persistence-WMWZJZ35.js +16 -0
- package/dist/learning-persistence-WMWZJZ35.js.map +1 -0
- package/dist/mcp-config-AUZQPUBY.js +12 -0
- package/dist/mcp-config-AUZQPUBY.js.map +1 -0
- package/dist/{model-capabilities-types-CSWO27YN.d.ts → model-capabilities-types-B57GZryc.d.ts} +1 -1
- package/dist/routing-memory-QY3XMU2R.js +13 -0
- package/dist/routing-memory-QY3XMU2R.js.map +1 -0
- package/dist/session-memory-3MBCE5KS.js +22 -0
- package/dist/session-memory-3MBCE5KS.js.map +1 -0
- package/dist/{setup-command-SS7LMN7Y.js → setup-command-IQ4MD3FT.js} +8 -5
- package/dist/setup-command-IQ4MD3FT.js.map +1 -0
- package/dist/setup-config-5YUPLDXF.js +10 -0
- package/dist/setup-config-5YUPLDXF.js.map +1 -0
- package/dist/weather-report-CC2C4KAX.js +15 -0
- package/dist/weather-report-CC2C4KAX.js.map +1 -0
- package/package.json +16 -18
- package/dist/chunk-L2SHSW4T.js.map +0 -1
- package/dist/chunk-LKSTILEE.js.map +0 -1
- package/dist/chunk-QZEAD6AG.js.map +0 -1
- package/dist/dist-H5XNXVAV.js.map +0 -1
- package/dist/setup-config-DSMOOLVW.js +0 -9
- /package/dist/{chunk-YSDUVCCZ.js.map → chunk-HH5LVGEE.js.map} +0 -0
- /package/dist/{chunk-E7EX2KQJ.js.map → chunk-HWDBNDUX.js.map} +0 -0
- /package/dist/{chunk-UGNLR4NZ.js.map → chunk-WSK4VSXP.js.map} +0 -0
- /package/dist/{doctor-deep-BDE2PHVX.js.map → composite-router-YPRWVTRB.js.map} +0 -0
- /package/dist/{setup-command-SS7LMN7Y.js.map → consensus-vote-DBE6RNZG.js.map} +0 -0
- /package/dist/{setup-config-DSMOOLVW.js.map → doctor-deep-AWE7SRU6.js.map} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runConfigInitSync
|
|
3
|
+
} from "./chunk-WSK4VSXP.js";
|
|
1
4
|
import {
|
|
2
5
|
VERSION,
|
|
3
6
|
initDataDirectories
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
runConfigInitSync
|
|
7
|
-
} from "./chunk-UGNLR4NZ.js";
|
|
7
|
+
} from "./chunk-5VZLXMO7.js";
|
|
8
8
|
import {
|
|
9
9
|
CLI_SUBPROCESS_TIMEOUTS,
|
|
10
10
|
createLogger,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
formatStatus,
|
|
14
14
|
getErrorMessage,
|
|
15
15
|
getTimeProvider
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IMWYKX4H.js";
|
|
17
17
|
|
|
18
18
|
// src/cli/setup-command.ts
|
|
19
19
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -1523,4 +1523,4 @@ export {
|
|
|
1523
1523
|
setupCommand,
|
|
1524
1524
|
setupCommandAsync
|
|
1525
1525
|
};
|
|
1526
|
-
//# sourceMappingURL=chunk-
|
|
1526
|
+
//# sourceMappingURL=chunk-HH5LVGEE.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
TASK_CATEGORIES,
|
|
3
3
|
getAdaptiveBonus,
|
|
4
4
|
getOutcomeStore
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-IMWYKX4H.js";
|
|
6
6
|
|
|
7
7
|
// src/cli/doctor-deep.ts
|
|
8
8
|
var CLI_NAMES = ["claude", "gemini", "codex", "opencode"];
|
|
@@ -106,4 +106,4 @@ export {
|
|
|
106
106
|
runDeepDiagnostics,
|
|
107
107
|
formatDeepDiagnostics
|
|
108
108
|
};
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-HWDBNDUX.js.map
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLogger,
|
|
3
|
+
err,
|
|
4
|
+
getErrorMessage,
|
|
5
|
+
getTimeProvider,
|
|
6
|
+
ok
|
|
7
|
+
} from "./chunk-IMWYKX4H.js";
|
|
8
|
+
|
|
9
|
+
// src/context/session-memory.ts
|
|
10
|
+
import * as fs from "fs";
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
|
|
13
|
+
// src/context/session-memory-types.ts
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
var SessionLearningSchema = z.object({
|
|
16
|
+
pattern: z.string().min(1),
|
|
17
|
+
context: z.string().min(1),
|
|
18
|
+
confidence: z.number().min(0).max(1),
|
|
19
|
+
source: z.string().optional()
|
|
20
|
+
});
|
|
21
|
+
var CompletedTaskSchema = z.object({
|
|
22
|
+
issue: z.union([z.string(), z.number()]).optional(),
|
|
23
|
+
approach: z.string().min(1),
|
|
24
|
+
challenges: z.array(z.string()),
|
|
25
|
+
durationMs: z.number().positive().optional()
|
|
26
|
+
});
|
|
27
|
+
var ResolvedErrorSchema = z.object({
|
|
28
|
+
error: z.string().min(1),
|
|
29
|
+
solution: z.string().min(1),
|
|
30
|
+
filePattern: z.string().optional()
|
|
31
|
+
});
|
|
32
|
+
var SessionEpisodeSchema = z.object({
|
|
33
|
+
sessionId: z.string().min(1),
|
|
34
|
+
date: z.string().min(1),
|
|
35
|
+
durationMs: z.number().min(0),
|
|
36
|
+
summary: z.string(),
|
|
37
|
+
learnings: z.array(SessionLearningSchema),
|
|
38
|
+
tasksCompleted: z.array(CompletedTaskSchema),
|
|
39
|
+
errorsResolved: z.array(ResolvedErrorSchema)
|
|
40
|
+
});
|
|
41
|
+
var SessionMemoryError = class extends Error {
|
|
42
|
+
constructor(message, context) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.context = context;
|
|
45
|
+
this.name = "SessionMemoryError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var DEFAULT_SESSION_MEMORY_CONFIG = {
|
|
49
|
+
maxEpisodesToLoad: 10,
|
|
50
|
+
maxLearningsInContext: 20,
|
|
51
|
+
minConfidenceThreshold: 0.5,
|
|
52
|
+
maxLearningsPerSession: 500,
|
|
53
|
+
maxTasksPerSession: 200,
|
|
54
|
+
maxErrorsPerSession: 200,
|
|
55
|
+
maxEpisodeFiles: 50
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/context/session-memory.ts
|
|
59
|
+
var SessionMemory = class {
|
|
60
|
+
memoryDir;
|
|
61
|
+
maxEpisodesToLoad;
|
|
62
|
+
maxLearningsInContext;
|
|
63
|
+
minConfidenceThreshold;
|
|
64
|
+
maxLearningsPerSession;
|
|
65
|
+
maxTasksPerSession;
|
|
66
|
+
maxErrorsPerSession;
|
|
67
|
+
maxEpisodeFiles;
|
|
68
|
+
log;
|
|
69
|
+
currentSession = null;
|
|
70
|
+
sessionStartTime = null;
|
|
71
|
+
constructor(config) {
|
|
72
|
+
const d = DEFAULT_SESSION_MEMORY_CONFIG;
|
|
73
|
+
this.memoryDir = config.memoryDir;
|
|
74
|
+
this.maxEpisodesToLoad = config.maxEpisodesToLoad ?? d.maxEpisodesToLoad;
|
|
75
|
+
this.maxLearningsInContext = config.maxLearningsInContext ?? d.maxLearningsInContext;
|
|
76
|
+
this.minConfidenceThreshold = config.minConfidenceThreshold ?? d.minConfidenceThreshold;
|
|
77
|
+
this.maxLearningsPerSession = config.maxLearningsPerSession ?? d.maxLearningsPerSession;
|
|
78
|
+
this.maxTasksPerSession = config.maxTasksPerSession ?? d.maxTasksPerSession;
|
|
79
|
+
this.maxErrorsPerSession = config.maxErrorsPerSession ?? d.maxErrorsPerSession;
|
|
80
|
+
this.maxEpisodeFiles = config.maxEpisodeFiles ?? d.maxEpisodeFiles;
|
|
81
|
+
this.log = config.logger ?? createLogger({ component: "SessionMemory" });
|
|
82
|
+
}
|
|
83
|
+
/** Start a new session and load relevant memories. */
|
|
84
|
+
startSession(sessionId) {
|
|
85
|
+
if (this.currentSession !== null) {
|
|
86
|
+
return err(
|
|
87
|
+
new SessionMemoryError("Session already in progress", {
|
|
88
|
+
existingSessionId: this.currentSession.sessionId
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
this.ensureMemoryDir();
|
|
93
|
+
this.sessionStartTime = getTimeProvider().now();
|
|
94
|
+
this.currentSession = {
|
|
95
|
+
sessionId,
|
|
96
|
+
date: getTimeProvider().nowDateString(),
|
|
97
|
+
durationMs: 0,
|
|
98
|
+
summary: "",
|
|
99
|
+
learnings: [],
|
|
100
|
+
tasksCompleted: [],
|
|
101
|
+
errorsResolved: []
|
|
102
|
+
};
|
|
103
|
+
this.log.info("Session started", { sessionId });
|
|
104
|
+
const relevantLearnings = this.loadRelevantLearnings();
|
|
105
|
+
return ok(relevantLearnings);
|
|
106
|
+
}
|
|
107
|
+
/** End the current session and persist episode. */
|
|
108
|
+
endSession(summary) {
|
|
109
|
+
if (this.currentSession === null || this.sessionStartTime === null) {
|
|
110
|
+
return err(new SessionMemoryError("No session in progress"));
|
|
111
|
+
}
|
|
112
|
+
const durationMs = getTimeProvider().now() - this.sessionStartTime;
|
|
113
|
+
const episode = {
|
|
114
|
+
...this.currentSession,
|
|
115
|
+
durationMs,
|
|
116
|
+
summary
|
|
117
|
+
};
|
|
118
|
+
const persistResult = this.persistEpisode(episode);
|
|
119
|
+
if (!persistResult.ok) return persistResult;
|
|
120
|
+
this.log.info("Session ended", {
|
|
121
|
+
sessionId: episode.sessionId,
|
|
122
|
+
durationMs,
|
|
123
|
+
learningsCount: episode.learnings.length,
|
|
124
|
+
tasksCount: episode.tasksCompleted.length
|
|
125
|
+
});
|
|
126
|
+
this.currentSession = null;
|
|
127
|
+
this.sessionStartTime = null;
|
|
128
|
+
return ok(episode);
|
|
129
|
+
}
|
|
130
|
+
/** Check if a session is currently active. */
|
|
131
|
+
isSessionActive() {
|
|
132
|
+
return this.currentSession !== null;
|
|
133
|
+
}
|
|
134
|
+
/** Get the current session ID. */
|
|
135
|
+
getCurrentSessionId() {
|
|
136
|
+
return this.currentSession?.sessionId ?? null;
|
|
137
|
+
}
|
|
138
|
+
/** Get learnings accumulated in the current (unpersisted) session. */
|
|
139
|
+
getCurrentSessionLearnings() {
|
|
140
|
+
return this.currentSession?.learnings ?? [];
|
|
141
|
+
}
|
|
142
|
+
/** Record a learning during the current session. */
|
|
143
|
+
recordLearning(learning) {
|
|
144
|
+
if (this.currentSession === null) {
|
|
145
|
+
return err(new SessionMemoryError("No session in progress"));
|
|
146
|
+
}
|
|
147
|
+
const validation = SessionLearningSchema.safeParse(learning);
|
|
148
|
+
if (!validation.success) {
|
|
149
|
+
return err(
|
|
150
|
+
new SessionMemoryError("Invalid learning data", {
|
|
151
|
+
errors: validation.error.issues
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
const updated = [...this.currentSession.learnings, learning];
|
|
156
|
+
if (updated.length > this.maxLearningsPerSession) {
|
|
157
|
+
updated.splice(0, updated.length - this.maxLearningsPerSession);
|
|
158
|
+
this.log.debug("Learning FIFO eviction", { kept: this.maxLearningsPerSession });
|
|
159
|
+
}
|
|
160
|
+
this.currentSession = { ...this.currentSession, learnings: updated };
|
|
161
|
+
this.log.debug("Learning recorded", { pattern: learning.pattern });
|
|
162
|
+
return ok(void 0);
|
|
163
|
+
}
|
|
164
|
+
/** Record a completed task during the current session. */
|
|
165
|
+
recordTask(task) {
|
|
166
|
+
if (this.currentSession === null) {
|
|
167
|
+
return err(new SessionMemoryError("No session in progress"));
|
|
168
|
+
}
|
|
169
|
+
const validation = CompletedTaskSchema.safeParse(task);
|
|
170
|
+
if (!validation.success) {
|
|
171
|
+
return err(
|
|
172
|
+
new SessionMemoryError("Invalid task data", {
|
|
173
|
+
errors: validation.error.issues
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
const updated = [...this.currentSession.tasksCompleted, task];
|
|
178
|
+
if (updated.length > this.maxTasksPerSession) {
|
|
179
|
+
updated.splice(0, updated.length - this.maxTasksPerSession);
|
|
180
|
+
this.log.debug("Task FIFO eviction", { kept: this.maxTasksPerSession });
|
|
181
|
+
}
|
|
182
|
+
this.currentSession = { ...this.currentSession, tasksCompleted: updated };
|
|
183
|
+
this.log.debug("Task recorded", { issue: task.issue });
|
|
184
|
+
return ok(void 0);
|
|
185
|
+
}
|
|
186
|
+
/** Record a resolved error during the current session. */
|
|
187
|
+
recordError(error) {
|
|
188
|
+
if (this.currentSession === null) {
|
|
189
|
+
return err(new SessionMemoryError("No session in progress"));
|
|
190
|
+
}
|
|
191
|
+
const validation = ResolvedErrorSchema.safeParse(error);
|
|
192
|
+
if (!validation.success) {
|
|
193
|
+
return err(
|
|
194
|
+
new SessionMemoryError("Invalid error data", {
|
|
195
|
+
errors: validation.error.issues
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
const updated = [...this.currentSession.errorsResolved, error];
|
|
200
|
+
if (updated.length > this.maxErrorsPerSession) {
|
|
201
|
+
updated.splice(0, updated.length - this.maxErrorsPerSession);
|
|
202
|
+
this.log.debug("Error FIFO eviction", { kept: this.maxErrorsPerSession });
|
|
203
|
+
}
|
|
204
|
+
this.currentSession = { ...this.currentSession, errorsResolved: updated };
|
|
205
|
+
this.log.debug("Error resolution recorded", { error: error.error });
|
|
206
|
+
return ok(void 0);
|
|
207
|
+
}
|
|
208
|
+
/** Load all episodes from the memory directory. */
|
|
209
|
+
loadEpisodes(limit) {
|
|
210
|
+
this.ensureMemoryDir();
|
|
211
|
+
const files = this.getEpisodeFiles();
|
|
212
|
+
const effectiveLimit = limit ?? this.maxEpisodesToLoad;
|
|
213
|
+
const episodes = [];
|
|
214
|
+
for (const file of files.slice(0, effectiveLimit)) {
|
|
215
|
+
const episode = this.loadEpisodeFile(file);
|
|
216
|
+
if (episode !== null) {
|
|
217
|
+
episodes.push(episode);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return episodes;
|
|
221
|
+
}
|
|
222
|
+
/** Load learnings relevant to the current context. */
|
|
223
|
+
loadRelevantLearnings() {
|
|
224
|
+
const episodes = this.loadEpisodes();
|
|
225
|
+
const allLearnings = [];
|
|
226
|
+
for (const episode of episodes) {
|
|
227
|
+
for (const learning of episode.learnings) {
|
|
228
|
+
if (learning.confidence >= this.minConfidenceThreshold) {
|
|
229
|
+
allLearnings.push(learning);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return allLearnings.sort((a, b) => b.confidence - a.confidence).slice(0, this.maxLearningsInContext);
|
|
234
|
+
}
|
|
235
|
+
/** Search for learnings matching a query (includes current session).
|
|
236
|
+
* Uses keyword-based matching: all query words must appear in the text. */
|
|
237
|
+
searchLearnings(query) {
|
|
238
|
+
const keywords = query.toLowerCase().split(/\s+/).filter((k) => k.length > 1);
|
|
239
|
+
const matches = [];
|
|
240
|
+
const episodes = this.loadEpisodes();
|
|
241
|
+
for (const episode of episodes) {
|
|
242
|
+
for (const learning of episode.learnings) {
|
|
243
|
+
if (matchesKeywords(learning, keywords)) {
|
|
244
|
+
matches.push(learning);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (this.currentSession !== null) {
|
|
249
|
+
for (const learning of this.currentSession.learnings) {
|
|
250
|
+
if (matchesKeywords(learning, keywords)) {
|
|
251
|
+
matches.push(learning);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return matches.sort((a, b) => b.confidence - a.confidence);
|
|
256
|
+
}
|
|
257
|
+
/** Get recent errors and their solutions. */
|
|
258
|
+
getRecentErrorSolutions(limit = 10) {
|
|
259
|
+
const episodes = this.loadEpisodes();
|
|
260
|
+
const errors = [];
|
|
261
|
+
for (const episode of episodes) {
|
|
262
|
+
errors.push(...episode.errorsResolved);
|
|
263
|
+
}
|
|
264
|
+
return errors.slice(0, limit);
|
|
265
|
+
}
|
|
266
|
+
ensureMemoryDir() {
|
|
267
|
+
if (!fs.existsSync(this.memoryDir)) {
|
|
268
|
+
fs.mkdirSync(this.memoryDir, { recursive: true });
|
|
269
|
+
this.log.debug("Created memory directory", { path: this.memoryDir });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
getEpisodeFiles() {
|
|
273
|
+
try {
|
|
274
|
+
const files = fs.readdirSync(this.memoryDir).filter((f) => f.startsWith("episode-") && f.endsWith(".json")).sort().reverse();
|
|
275
|
+
return files;
|
|
276
|
+
} catch {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
loadEpisodeFile(filename) {
|
|
281
|
+
try {
|
|
282
|
+
const filepath = path.join(this.memoryDir, filename);
|
|
283
|
+
const content = fs.readFileSync(filepath, "utf-8");
|
|
284
|
+
const data = JSON.parse(content);
|
|
285
|
+
const validation = SessionEpisodeSchema.safeParse(data);
|
|
286
|
+
if (validation.success) {
|
|
287
|
+
return validation.data;
|
|
288
|
+
}
|
|
289
|
+
this.log.warn("Invalid episode file", { filename, errors: validation.error.issues });
|
|
290
|
+
return null;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
this.log.warn("Failed to load episode file", { filename, error });
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
persistEpisode(episode) {
|
|
297
|
+
try {
|
|
298
|
+
this.ensureMemoryDir();
|
|
299
|
+
const sessionSuffix = episode.sessionId.replace(/[^a-zA-Z0-9-]/g, "-").slice(0, 16);
|
|
300
|
+
const timestamp = getTimeProvider().now().toString(36);
|
|
301
|
+
const filename = `episode-${episode.date}-${sessionSuffix}-${timestamp}.json`;
|
|
302
|
+
const filepath = path.join(this.memoryDir, filename);
|
|
303
|
+
const content = JSON.stringify(episode, null, 2);
|
|
304
|
+
fs.writeFileSync(filepath, content, "utf-8");
|
|
305
|
+
this.log.debug("Episode persisted", { filename });
|
|
306
|
+
this.enforceEpisodeRetention();
|
|
307
|
+
return ok(void 0);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
const message = getErrorMessage(error);
|
|
310
|
+
return err(new SessionMemoryError(`Failed to persist episode: ${message}`));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Delete oldest episode files when count exceeds maxEpisodeFiles. */
|
|
314
|
+
enforceEpisodeRetention() {
|
|
315
|
+
try {
|
|
316
|
+
const files = this.getEpisodeFiles();
|
|
317
|
+
if (files.length <= this.maxEpisodeFiles) return;
|
|
318
|
+
const toDelete = files.slice(this.maxEpisodeFiles);
|
|
319
|
+
for (const file of toDelete) {
|
|
320
|
+
fs.unlinkSync(path.join(this.memoryDir, file));
|
|
321
|
+
}
|
|
322
|
+
this.log.info("Episode retention enforced", {
|
|
323
|
+
kept: this.maxEpisodeFiles,
|
|
324
|
+
deleted: toDelete.length
|
|
325
|
+
});
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this.log.debug("Episode retention cleanup failed", {
|
|
328
|
+
error: getErrorMessage(error)
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
function matchesKeywords(learning, keywords) {
|
|
334
|
+
if (keywords.length === 0) return false;
|
|
335
|
+
const text = `${learning.pattern} ${learning.context}`.toLowerCase();
|
|
336
|
+
return keywords.every((k) => text.includes(k));
|
|
337
|
+
}
|
|
338
|
+
function createSessionMemory(memoryDir, config) {
|
|
339
|
+
return new SessionMemory({
|
|
340
|
+
memoryDir,
|
|
341
|
+
...config
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export {
|
|
346
|
+
SessionLearningSchema,
|
|
347
|
+
CompletedTaskSchema,
|
|
348
|
+
ResolvedErrorSchema,
|
|
349
|
+
SessionEpisodeSchema,
|
|
350
|
+
SessionMemoryError,
|
|
351
|
+
SessionMemory,
|
|
352
|
+
createSessionMemory
|
|
353
|
+
};
|
|
354
|
+
//# sourceMappingURL=chunk-I6YDS23R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context/session-memory.ts","../src/context/session-memory-types.ts"],"sourcesContent":["/**\n * Cross-session episodic memory persistence with FIFO eviction bounds.\n * @module context/session-memory\n * (Source: Issue #130, #709 - arXiv:2303.11366 - Reflexion)\n */\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport { getErrorMessage, getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/logger.js';\nimport { createLogger } from '../core/logger.js';\nimport type {\n SessionLearning,\n CompletedTask,\n ResolvedError,\n SessionEpisode,\n SessionMemoryConfig,\n} from './session-memory-types.js';\nimport {\n SessionLearningSchema,\n CompletedTaskSchema,\n ResolvedErrorSchema,\n SessionEpisodeSchema,\n SessionMemoryError,\n DEFAULT_SESSION_MEMORY_CONFIG,\n} from './session-memory-types.js';\n\nexport type {\n SessionLearning,\n CompletedTask,\n ResolvedError,\n SessionEpisode,\n SessionMemoryConfig,\n} from './session-memory-types.js';\nexport {\n SessionLearningSchema,\n CompletedTaskSchema,\n ResolvedErrorSchema,\n SessionEpisodeSchema,\n SessionMemoryError,\n} from './session-memory-types.js';\n\n/** Manages cross-session episodic memory with per-session bounds and disk retention. */\nexport class SessionMemory {\n private readonly memoryDir: string;\n private readonly maxEpisodesToLoad: number;\n private readonly maxLearningsInContext: number;\n private readonly minConfidenceThreshold: number;\n private readonly maxLearningsPerSession: number;\n private readonly maxTasksPerSession: number;\n private readonly maxErrorsPerSession: number;\n private readonly maxEpisodeFiles: number;\n private readonly log: ILogger;\n private currentSession: SessionEpisode | null = null;\n private sessionStartTime: number | null = null;\n\n constructor(config: SessionMemoryConfig) {\n const d = DEFAULT_SESSION_MEMORY_CONFIG;\n this.memoryDir = config.memoryDir;\n this.maxEpisodesToLoad = config.maxEpisodesToLoad ?? d.maxEpisodesToLoad;\n this.maxLearningsInContext = config.maxLearningsInContext ?? d.maxLearningsInContext;\n this.minConfidenceThreshold = config.minConfidenceThreshold ?? d.minConfidenceThreshold;\n this.maxLearningsPerSession = config.maxLearningsPerSession ?? d.maxLearningsPerSession;\n this.maxTasksPerSession = config.maxTasksPerSession ?? d.maxTasksPerSession;\n this.maxErrorsPerSession = config.maxErrorsPerSession ?? d.maxErrorsPerSession;\n this.maxEpisodeFiles = config.maxEpisodeFiles ?? d.maxEpisodeFiles;\n this.log = config.logger ?? createLogger({ component: 'SessionMemory' });\n }\n\n /** Start a new session and load relevant memories. */\n startSession(sessionId: string): Result<readonly SessionLearning[], SessionMemoryError> {\n if (this.currentSession !== null) {\n return err(\n new SessionMemoryError('Session already in progress', {\n existingSessionId: this.currentSession.sessionId,\n })\n );\n }\n\n this.ensureMemoryDir();\n this.sessionStartTime = getTimeProvider().now();\n\n this.currentSession = {\n sessionId,\n date: getTimeProvider().nowDateString(),\n durationMs: 0,\n summary: '',\n learnings: [],\n tasksCompleted: [],\n errorsResolved: [],\n };\n\n this.log.info('Session started', { sessionId });\n\n // Load relevant learnings from past episodes\n const relevantLearnings = this.loadRelevantLearnings();\n return ok(relevantLearnings);\n }\n\n /** End the current session and persist episode. */\n endSession(summary: string): Result<SessionEpisode, SessionMemoryError> {\n if (this.currentSession === null || this.sessionStartTime === null) {\n return err(new SessionMemoryError('No session in progress'));\n }\n\n const durationMs = getTimeProvider().now() - this.sessionStartTime;\n const episode: SessionEpisode = {\n ...this.currentSession,\n durationMs,\n summary,\n };\n\n const persistResult = this.persistEpisode(episode);\n if (!persistResult.ok) return persistResult;\n\n this.log.info('Session ended', {\n sessionId: episode.sessionId,\n durationMs,\n learningsCount: episode.learnings.length,\n tasksCount: episode.tasksCompleted.length,\n });\n\n this.currentSession = null;\n this.sessionStartTime = null;\n\n return ok(episode);\n }\n\n /** Check if a session is currently active. */\n isSessionActive(): boolean {\n return this.currentSession !== null;\n }\n\n /** Get the current session ID. */\n getCurrentSessionId(): string | null {\n return this.currentSession?.sessionId ?? null;\n }\n\n /** Get learnings accumulated in the current (unpersisted) session. */\n getCurrentSessionLearnings(): readonly SessionLearning[] {\n return this.currentSession?.learnings ?? [];\n }\n\n /** Record a learning during the current session. */\n recordLearning(learning: SessionLearning): Result<void, SessionMemoryError> {\n if (this.currentSession === null) {\n return err(new SessionMemoryError('No session in progress'));\n }\n\n const validation = SessionLearningSchema.safeParse(learning);\n if (!validation.success) {\n return err(\n new SessionMemoryError('Invalid learning data', {\n errors: validation.error.issues,\n })\n );\n }\n\n const updated = [...this.currentSession.learnings, learning];\n if (updated.length > this.maxLearningsPerSession) {\n updated.splice(0, updated.length - this.maxLearningsPerSession);\n this.log.debug('Learning FIFO eviction', { kept: this.maxLearningsPerSession });\n }\n this.currentSession = { ...this.currentSession, learnings: updated };\n\n this.log.debug('Learning recorded', { pattern: learning.pattern });\n return ok(undefined);\n }\n\n /** Record a completed task during the current session. */\n recordTask(task: CompletedTask): Result<void, SessionMemoryError> {\n if (this.currentSession === null) {\n return err(new SessionMemoryError('No session in progress'));\n }\n\n const validation = CompletedTaskSchema.safeParse(task);\n if (!validation.success) {\n return err(\n new SessionMemoryError('Invalid task data', {\n errors: validation.error.issues,\n })\n );\n }\n\n const updated = [...this.currentSession.tasksCompleted, task];\n if (updated.length > this.maxTasksPerSession) {\n updated.splice(0, updated.length - this.maxTasksPerSession);\n this.log.debug('Task FIFO eviction', { kept: this.maxTasksPerSession });\n }\n this.currentSession = { ...this.currentSession, tasksCompleted: updated };\n\n this.log.debug('Task recorded', { issue: task.issue });\n return ok(undefined);\n }\n\n /** Record a resolved error during the current session. */\n recordError(error: ResolvedError): Result<void, SessionMemoryError> {\n if (this.currentSession === null) {\n return err(new SessionMemoryError('No session in progress'));\n }\n\n const validation = ResolvedErrorSchema.safeParse(error);\n if (!validation.success) {\n return err(\n new SessionMemoryError('Invalid error data', {\n errors: validation.error.issues,\n })\n );\n }\n\n const updated = [...this.currentSession.errorsResolved, error];\n if (updated.length > this.maxErrorsPerSession) {\n updated.splice(0, updated.length - this.maxErrorsPerSession);\n this.log.debug('Error FIFO eviction', { kept: this.maxErrorsPerSession });\n }\n this.currentSession = { ...this.currentSession, errorsResolved: updated };\n\n this.log.debug('Error resolution recorded', { error: error.error });\n return ok(undefined);\n }\n\n /** Load all episodes from the memory directory. */\n loadEpisodes(limit?: number): readonly SessionEpisode[] {\n this.ensureMemoryDir();\n const files = this.getEpisodeFiles();\n const effectiveLimit = limit ?? this.maxEpisodesToLoad;\n\n const episodes: SessionEpisode[] = [];\n for (const file of files.slice(0, effectiveLimit)) {\n const episode = this.loadEpisodeFile(file);\n if (episode !== null) {\n episodes.push(episode);\n }\n }\n\n return episodes;\n }\n\n /** Load learnings relevant to the current context. */\n loadRelevantLearnings(): readonly SessionLearning[] {\n const episodes = this.loadEpisodes();\n const allLearnings: SessionLearning[] = [];\n\n for (const episode of episodes) {\n for (const learning of episode.learnings) {\n if (learning.confidence >= this.minConfidenceThreshold) {\n allLearnings.push(learning);\n }\n }\n }\n\n // Sort by confidence (highest first) and limit\n return allLearnings\n .sort((a, b) => b.confidence - a.confidence)\n .slice(0, this.maxLearningsInContext);\n }\n\n /** Search for learnings matching a query (includes current session).\n * Uses keyword-based matching: all query words must appear in the text. */\n searchLearnings(query: string): readonly SessionLearning[] {\n const keywords = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((k) => k.length > 1);\n const matches: SessionLearning[] = [];\n\n // Search persisted episodes\n const episodes = this.loadEpisodes();\n for (const episode of episodes) {\n for (const learning of episode.learnings) {\n if (matchesKeywords(learning, keywords)) {\n matches.push(learning);\n }\n }\n }\n\n // Include current (unpersisted) session learnings (#1126)\n if (this.currentSession !== null) {\n for (const learning of this.currentSession.learnings) {\n if (matchesKeywords(learning, keywords)) {\n matches.push(learning);\n }\n }\n }\n\n return matches.sort((a, b) => b.confidence - a.confidence);\n }\n\n /** Get recent errors and their solutions. */\n getRecentErrorSolutions(limit = 10): readonly ResolvedError[] {\n const episodes = this.loadEpisodes();\n const errors: ResolvedError[] = [];\n\n for (const episode of episodes) {\n errors.push(...episode.errorsResolved);\n }\n\n return errors.slice(0, limit);\n }\n\n private ensureMemoryDir(): void {\n if (!fs.existsSync(this.memoryDir)) {\n fs.mkdirSync(this.memoryDir, { recursive: true });\n this.log.debug('Created memory directory', { path: this.memoryDir });\n }\n }\n\n private getEpisodeFiles(): readonly string[] {\n try {\n const files = fs\n .readdirSync(this.memoryDir)\n .filter((f) => f.startsWith('episode-') && f.endsWith('.json'))\n .sort()\n .reverse(); // Most recent first\n return files;\n } catch {\n return [];\n }\n }\n\n private loadEpisodeFile(filename: string): SessionEpisode | null {\n try {\n const filepath = path.join(this.memoryDir, filename);\n const content = fs.readFileSync(filepath, 'utf-8');\n const data = JSON.parse(content) as unknown;\n const validation = SessionEpisodeSchema.safeParse(data);\n if (validation.success) {\n // Cast required due to exactOptionalPropertyTypes - Zod validated the data\n return validation.data as SessionEpisode;\n }\n this.log.warn('Invalid episode file', { filename, errors: validation.error.issues });\n return null;\n } catch (error) {\n this.log.warn('Failed to load episode file', { filename, error });\n return null;\n }\n }\n\n private persistEpisode(episode: SessionEpisode): Result<void, SessionMemoryError> {\n try {\n this.ensureMemoryDir();\n // Use more of session ID to avoid collisions\n const sessionSuffix = episode.sessionId.replace(/[^a-zA-Z0-9-]/g, '-').slice(0, 16);\n const timestamp = getTimeProvider().now().toString(36); // Base36 timestamp for uniqueness\n const filename = `episode-${episode.date}-${sessionSuffix}-${timestamp}.json`;\n const filepath = path.join(this.memoryDir, filename);\n const content = JSON.stringify(episode, null, 2);\n fs.writeFileSync(filepath, content, 'utf-8');\n this.log.debug('Episode persisted', { filename });\n this.enforceEpisodeRetention();\n return ok(undefined);\n } catch (error) {\n const message = getErrorMessage(error);\n return err(new SessionMemoryError(`Failed to persist episode: ${message}`));\n }\n }\n\n /** Delete oldest episode files when count exceeds maxEpisodeFiles. */\n private enforceEpisodeRetention(): void {\n try {\n const files = this.getEpisodeFiles(); // sorted most-recent-first\n if (files.length <= this.maxEpisodeFiles) return;\n const toDelete = files.slice(this.maxEpisodeFiles);\n for (const file of toDelete) {\n fs.unlinkSync(path.join(this.memoryDir, file));\n }\n this.log.info('Episode retention enforced', {\n kept: this.maxEpisodeFiles,\n deleted: toDelete.length,\n });\n } catch (error: unknown) {\n this.log.debug('Episode retention cleanup failed', {\n error: getErrorMessage(error),\n });\n }\n }\n}\n\n/** Check if a learning matches all keywords (AND logic). */\nfunction matchesKeywords(learning: SessionLearning, keywords: readonly string[]): boolean {\n if (keywords.length === 0) return false;\n const text = `${learning.pattern} ${learning.context}`.toLowerCase();\n return keywords.every((k) => text.includes(k));\n}\n\n/** Create a SessionMemory instance with default configuration. */\nexport function createSessionMemory(\n memoryDir: string,\n config?: Partial<Omit<SessionMemoryConfig, 'memoryDir'>>\n): SessionMemory {\n return new SessionMemory({\n memoryDir,\n ...config,\n });\n}\n","/**\n * Session Memory Types and Schemas\n *\n * Type definitions for cross-session episodic memory persistence.\n *\n * @module context/session-memory-types\n * (Source: Issue #130, arXiv:2303.11366 - Reflexion)\n */\n\nimport { z } from 'zod';\nimport type { ILogger } from '../core/logger.js';\n\n// ============================================================================\n// Session Learning\n// ============================================================================\n\n/**\n * A learning captured during a session.\n */\nexport interface SessionLearning {\n /** The pattern or technique learned */\n readonly pattern: string;\n /** Context where this learning applies */\n readonly context: string;\n /** Confidence in this learning (0-1) */\n readonly confidence: number;\n /** Optional source (e.g., task, error, user feedback) */\n readonly source?: string;\n}\n\nexport const SessionLearningSchema = z.object({\n pattern: z.string().min(1),\n context: z.string().min(1),\n confidence: z.number().min(0).max(1),\n source: z.string().optional(),\n});\n\n// ============================================================================\n// Completed Task\n// ============================================================================\n\n/**\n * A task completed during a session.\n */\nexport interface CompletedTask {\n /** Issue or task identifier */\n readonly issue?: string | number;\n /** Approach used to complete the task */\n readonly approach: string;\n /** Challenges encountered */\n readonly challenges: readonly string[];\n /** Duration in milliseconds */\n readonly durationMs?: number;\n}\n\nexport const CompletedTaskSchema = z.object({\n issue: z.union([z.string(), z.number()]).optional(),\n approach: z.string().min(1),\n challenges: z.array(z.string()),\n durationMs: z.number().positive().optional(),\n});\n\n// ============================================================================\n// Resolved Error\n// ============================================================================\n\n/**\n * An error resolved during a session.\n */\nexport interface ResolvedError {\n /** Error message or type */\n readonly error: string;\n /** Solution applied */\n readonly solution: string;\n /** File pattern where this applies */\n readonly filePattern?: string;\n}\n\nexport const ResolvedErrorSchema = z.object({\n error: z.string().min(1),\n solution: z.string().min(1),\n filePattern: z.string().optional(),\n});\n\n// ============================================================================\n// Session Episode\n// ============================================================================\n\n/**\n * Complete session episode data.\n */\nexport interface SessionEpisode {\n /** Unique session identifier */\n readonly sessionId: string;\n /** Session date (ISO format) */\n readonly date: string;\n /** Session duration in milliseconds */\n readonly durationMs: number;\n /** Brief summary of the session */\n readonly summary: string;\n /** Learnings captured */\n readonly learnings: readonly SessionLearning[];\n /** Tasks completed */\n readonly tasksCompleted: readonly CompletedTask[];\n /** Errors resolved */\n readonly errorsResolved: readonly ResolvedError[];\n}\n\nexport const SessionEpisodeSchema = z.object({\n sessionId: z.string().min(1),\n date: z.string().min(1),\n durationMs: z.number().min(0),\n summary: z.string(),\n learnings: z.array(SessionLearningSchema),\n tasksCompleted: z.array(CompletedTaskSchema),\n errorsResolved: z.array(ResolvedErrorSchema),\n});\n\n// ============================================================================\n// Error Class\n// ============================================================================\n\n/**\n * Error for session memory operations.\n */\nexport class SessionMemoryError extends Error {\n constructor(\n message: string,\n public readonly context?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'SessionMemoryError';\n }\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/**\n * Configuration for SessionMemory.\n */\nexport interface SessionMemoryConfig {\n /** Base directory for memory storage */\n readonly memoryDir: string;\n /** Maximum episodes to load on session start */\n readonly maxEpisodesToLoad?: number;\n /** Maximum learnings to include in context */\n readonly maxLearningsInContext?: number;\n /** Minimum confidence threshold for learnings */\n readonly minConfidenceThreshold?: number;\n /** Maximum learnings per session (FIFO eviction). */\n readonly maxLearningsPerSession?: number;\n /** Maximum tasks per session (FIFO eviction). */\n readonly maxTasksPerSession?: number;\n /** Maximum errors per session (FIFO eviction). */\n readonly maxErrorsPerSession?: number;\n /** Maximum episode files to retain on disk. Oldest are deleted. */\n readonly maxEpisodeFiles?: number;\n /** Logger instance */\n readonly logger?: ILogger;\n}\n\nexport const DEFAULT_SESSION_MEMORY_CONFIG = {\n maxEpisodesToLoad: 10,\n maxLearningsInContext: 20,\n minConfidenceThreshold: 0.5,\n maxLearningsPerSession: 500,\n maxTasksPerSession: 200,\n maxErrorsPerSession: 200,\n maxEpisodeFiles: 50,\n} as const;\n"],"mappings":"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","names":[]}
|