claude-memory-layer 1.0.6 → 1.0.8
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/.claude/settings.local.json +4 -1
- package/.claude-plugin/plugin.json +3 -3
- package/.history/package_20260201142928.json +46 -0
- package/.history/package_20260201192048.json +47 -0
- package/README.md +26 -26
- package/dist/.claude-plugin/plugin.json +3 -3
- package/dist/cli/index.js +1109 -25
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +192 -5
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/session-end.js +262 -18
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +262 -18
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +262 -18
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +262 -18
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/server/api/index.js +4728 -0
- package/dist/server/api/index.js.map +7 -0
- package/dist/server/index.js +4790 -0
- package/dist/server/index.js.map +7 -0
- package/dist/services/memory-service.js +269 -18
- package/dist/services/memory-service.js.map +4 -4
- package/dist/ui/index.html +1225 -0
- package/package.json +4 -2
- package/scripts/build.ts +33 -3
- package/src/cli/index.ts +311 -6
- package/src/core/db-wrapper.ts +8 -1
- package/src/core/event-store.ts +52 -3
- package/src/core/graduation-worker.ts +171 -0
- package/src/core/graduation.ts +15 -2
- package/src/core/index.ts +1 -0
- package/src/core/retriever.ts +18 -0
- package/src/core/types.ts +1 -1
- package/src/mcp/index.ts +2 -2
- package/src/mcp/tools.ts +1 -1
- package/src/server/api/citations.ts +7 -3
- package/src/server/api/events.ts +7 -3
- package/src/server/api/search.ts +7 -3
- package/src/server/api/sessions.ts +7 -3
- package/src/server/api/stats.ts +175 -5
- package/src/server/index.ts +18 -9
- package/src/services/memory-service.ts +107 -19
- package/src/ui/index.html +1225 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graduation Worker
|
|
3
|
+
* Periodically evaluates memory events for promotion to higher levels
|
|
4
|
+
* L0 → L1 → L2 → L3 → L4 based on access patterns and confidence
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { MemoryLevel } from './types.js';
|
|
8
|
+
import { EventStore } from './event-store.js';
|
|
9
|
+
import { GraduationPipeline } from './graduation.js';
|
|
10
|
+
|
|
11
|
+
export interface GraduationWorkerConfig {
|
|
12
|
+
/** How often to run graduation evaluation (ms) */
|
|
13
|
+
evaluationIntervalMs: number;
|
|
14
|
+
/** Batch size for graduation evaluation */
|
|
15
|
+
batchSize: number;
|
|
16
|
+
/** Minimum time between evaluations of the same event (ms) */
|
|
17
|
+
cooldownMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DEFAULT_CONFIG: GraduationWorkerConfig = {
|
|
21
|
+
evaluationIntervalMs: 300000, // 5 minutes
|
|
22
|
+
batchSize: 50,
|
|
23
|
+
cooldownMs: 3600000 // 1 hour cooldown between evaluations
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export class GraduationWorker {
|
|
27
|
+
private running = false;
|
|
28
|
+
private timeout: NodeJS.Timeout | null = null;
|
|
29
|
+
private lastEvaluated: Map<string, number> = new Map();
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
private eventStore: EventStore,
|
|
33
|
+
private graduation: GraduationPipeline,
|
|
34
|
+
private config: GraduationWorkerConfig = DEFAULT_CONFIG
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Start the graduation worker
|
|
39
|
+
*/
|
|
40
|
+
start(): void {
|
|
41
|
+
if (this.running) return;
|
|
42
|
+
this.running = true;
|
|
43
|
+
this.scheduleNext();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Stop the graduation worker
|
|
48
|
+
*/
|
|
49
|
+
stop(): void {
|
|
50
|
+
this.running = false;
|
|
51
|
+
if (this.timeout) {
|
|
52
|
+
clearTimeout(this.timeout);
|
|
53
|
+
this.timeout = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if currently running
|
|
59
|
+
*/
|
|
60
|
+
isRunning(): boolean {
|
|
61
|
+
return this.running;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Force a graduation evaluation run
|
|
66
|
+
*/
|
|
67
|
+
async forceRun(): Promise<GraduationRunResult> {
|
|
68
|
+
return await this.runGraduation();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Schedule the next graduation check
|
|
73
|
+
*/
|
|
74
|
+
private scheduleNext(): void {
|
|
75
|
+
if (!this.running) return;
|
|
76
|
+
|
|
77
|
+
this.timeout = setTimeout(
|
|
78
|
+
() => this.run(),
|
|
79
|
+
this.config.evaluationIntervalMs
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Run graduation evaluation
|
|
85
|
+
*/
|
|
86
|
+
private async run(): Promise<void> {
|
|
87
|
+
if (!this.running) return;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await this.runGraduation();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('Graduation error:', error);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.scheduleNext();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Perform graduation evaluation across all levels
|
|
100
|
+
*/
|
|
101
|
+
private async runGraduation(): Promise<GraduationRunResult> {
|
|
102
|
+
const result: GraduationRunResult = {
|
|
103
|
+
evaluated: 0,
|
|
104
|
+
graduated: 0,
|
|
105
|
+
byLevel: {}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const levels: MemoryLevel[] = ['L0', 'L1', 'L2', 'L3'];
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
|
|
111
|
+
for (const level of levels) {
|
|
112
|
+
const events = await this.eventStore.getEventsByLevel(level, {
|
|
113
|
+
limit: this.config.batchSize
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
let levelGraduated = 0;
|
|
117
|
+
|
|
118
|
+
for (const event of events) {
|
|
119
|
+
// Check cooldown
|
|
120
|
+
const lastEval = this.lastEvaluated.get(event.id);
|
|
121
|
+
if (lastEval && (now - lastEval) < this.config.cooldownMs) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
result.evaluated++;
|
|
126
|
+
this.lastEvaluated.set(event.id, now);
|
|
127
|
+
|
|
128
|
+
const gradResult = await this.graduation.evaluateGraduation(event.id, level);
|
|
129
|
+
|
|
130
|
+
if (gradResult.success) {
|
|
131
|
+
result.graduated++;
|
|
132
|
+
levelGraduated++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (levelGraduated > 0) {
|
|
137
|
+
result.byLevel[level] = levelGraduated;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Clean up old cooldown entries (keep last 1000)
|
|
142
|
+
if (this.lastEvaluated.size > 1000) {
|
|
143
|
+
const entries = Array.from(this.lastEvaluated.entries());
|
|
144
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
145
|
+
this.lastEvaluated = new Map(entries.slice(0, 1000));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface GraduationRunResult {
|
|
153
|
+
evaluated: number;
|
|
154
|
+
graduated: number;
|
|
155
|
+
byLevel: Record<string, number>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create a Graduation Worker instance
|
|
160
|
+
*/
|
|
161
|
+
export function createGraduationWorker(
|
|
162
|
+
eventStore: EventStore,
|
|
163
|
+
graduation: GraduationPipeline,
|
|
164
|
+
config?: Partial<GraduationWorkerConfig>
|
|
165
|
+
): GraduationWorker {
|
|
166
|
+
return new GraduationWorker(
|
|
167
|
+
eventStore,
|
|
168
|
+
graduation,
|
|
169
|
+
{ ...DEFAULT_CONFIG, ...config }
|
|
170
|
+
);
|
|
171
|
+
}
|
package/src/core/graduation.ts
CHANGED
|
@@ -84,18 +84,31 @@ export class GraduationPipeline {
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Track which sessions have accessed each event
|
|
88
|
+
private readonly sessionAccesses: Map<string, Set<string>> = new Map();
|
|
89
|
+
|
|
87
90
|
/**
|
|
88
91
|
* Record an access to an event (used for graduation scoring)
|
|
89
92
|
*/
|
|
90
93
|
recordAccess(eventId: string, fromSessionId: string, confidence: number = 1.0): void {
|
|
91
94
|
const existing = this.metrics.get(eventId);
|
|
92
95
|
|
|
96
|
+
// Track sessions that have accessed this event
|
|
97
|
+
if (!this.sessionAccesses.has(eventId)) {
|
|
98
|
+
this.sessionAccesses.set(eventId, new Set());
|
|
99
|
+
}
|
|
100
|
+
const sessions = this.sessionAccesses.get(eventId)!;
|
|
101
|
+
const isNewSession = !sessions.has(fromSessionId);
|
|
102
|
+
sessions.add(fromSessionId);
|
|
103
|
+
|
|
93
104
|
if (existing) {
|
|
94
105
|
existing.accessCount++;
|
|
95
106
|
existing.lastAccessed = new Date();
|
|
96
107
|
existing.confidence = Math.max(existing.confidence, confidence);
|
|
97
|
-
//
|
|
98
|
-
|
|
108
|
+
// Update cross-session references count
|
|
109
|
+
if (isNewSession && sessions.size > 1) {
|
|
110
|
+
existing.crossSessionRefs = sessions.size - 1;
|
|
111
|
+
}
|
|
99
112
|
} else {
|
|
100
113
|
this.metrics.set(eventId, {
|
|
101
114
|
eventId,
|
package/src/core/index.ts
CHANGED
package/src/core/retriever.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { Embedder } from './embedder.js';
|
|
|
9
9
|
import { Matcher } from './matcher.js';
|
|
10
10
|
import { SharedStore } from './shared-store.js';
|
|
11
11
|
import { SharedVectorStore } from './shared-vector-store.js';
|
|
12
|
+
import { GraduationPipeline } from './graduation.js';
|
|
12
13
|
import type { MemoryEvent, MatchResult, Config, SharedTroubleshootingEntry } from './types.js';
|
|
13
14
|
|
|
14
15
|
export interface RetrievalOptions {
|
|
@@ -60,6 +61,7 @@ export class Retriever {
|
|
|
60
61
|
private readonly matcher: Matcher;
|
|
61
62
|
private sharedStore?: SharedStore;
|
|
62
63
|
private sharedVectorStore?: SharedVectorStore;
|
|
64
|
+
private graduation?: GraduationPipeline;
|
|
63
65
|
|
|
64
66
|
constructor(
|
|
65
67
|
eventStore: EventStore,
|
|
@@ -76,6 +78,13 @@ export class Retriever {
|
|
|
76
78
|
this.sharedVectorStore = sharedOptions?.sharedVectorStore;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Set graduation pipeline for access tracking
|
|
83
|
+
*/
|
|
84
|
+
setGraduationPipeline(graduation: GraduationPipeline): void {
|
|
85
|
+
this.graduation = graduation;
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
/**
|
|
80
89
|
* Set shared stores after construction
|
|
81
90
|
*/
|
|
@@ -237,6 +246,15 @@ export class Retriever {
|
|
|
237
246
|
const event = await this.eventStore.getEvent(result.eventId);
|
|
238
247
|
if (!event) continue;
|
|
239
248
|
|
|
249
|
+
// Record access for graduation scoring
|
|
250
|
+
if (this.graduation) {
|
|
251
|
+
this.graduation.recordAccess(
|
|
252
|
+
event.id,
|
|
253
|
+
options.sessionId || 'unknown',
|
|
254
|
+
result.score
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
240
258
|
let sessionContext: string | undefined;
|
|
241
259
|
if (options.includeSessionContext) {
|
|
242
260
|
sessionContext = await this.getSessionContext(event.sessionId, event.id);
|
package/src/core/types.ts
CHANGED
package/src/mcp/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { handleToolCall } from './handlers.js';
|
|
|
16
16
|
|
|
17
17
|
const server = new Server(
|
|
18
18
|
{
|
|
19
|
-
name: '
|
|
19
|
+
name: 'claude-memory-layer-mcp',
|
|
20
20
|
version: '1.0.0'
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -41,7 +41,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
41
41
|
async function main() {
|
|
42
42
|
const transport = new StdioServerTransport();
|
|
43
43
|
await server.connect(transport);
|
|
44
|
-
console.error('
|
|
44
|
+
console.error('claude-memory-layer MCP server started');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
main().catch(console.error);
|
package/src/mcp/tools.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
|
8
8
|
export const tools: Tool[] = [
|
|
9
9
|
{
|
|
10
10
|
name: 'mem-search',
|
|
11
|
-
description: 'Search
|
|
11
|
+
description: 'Search claude-memory-layer for relevant past conversations and insights. Returns a compact index of results - use mem-details to get full content.',
|
|
12
12
|
inputSchema: {
|
|
13
13
|
type: 'object',
|
|
14
14
|
properties: {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Hono } from 'hono';
|
|
7
|
-
import {
|
|
7
|
+
import { getReadOnlyMemoryService } from '../../services/memory-service.js';
|
|
8
8
|
import { generateCitationId, parseCitationId } from '../../core/citation-generator.js';
|
|
9
9
|
|
|
10
10
|
export const citationsRouter = new Hono();
|
|
@@ -15,9 +15,9 @@ citationsRouter.get('/:id', async (c) => {
|
|
|
15
15
|
|
|
16
16
|
// Support both formats: "a7Bc3x" or "mem:a7Bc3x"
|
|
17
17
|
const citationId = parseCitationId(id) || id;
|
|
18
|
+
const memoryService = getReadOnlyMemoryService();
|
|
18
19
|
|
|
19
20
|
try {
|
|
20
|
-
const memoryService = getDefaultMemoryService();
|
|
21
21
|
await memoryService.initialize();
|
|
22
22
|
|
|
23
23
|
// Search through recent events to find the one matching this citation ID
|
|
@@ -48,6 +48,8 @@ citationsRouter.get('/:id', async (c) => {
|
|
|
48
48
|
});
|
|
49
49
|
} catch (error) {
|
|
50
50
|
return c.json({ error: (error as Error).message }, 500);
|
|
51
|
+
} finally {
|
|
52
|
+
await memoryService.shutdown();
|
|
51
53
|
}
|
|
52
54
|
});
|
|
53
55
|
|
|
@@ -55,9 +57,9 @@ citationsRouter.get('/:id', async (c) => {
|
|
|
55
57
|
citationsRouter.get('/:id/related', async (c) => {
|
|
56
58
|
const { id } = c.req.param();
|
|
57
59
|
const citationId = parseCitationId(id) || id;
|
|
60
|
+
const memoryService = getReadOnlyMemoryService();
|
|
58
61
|
|
|
59
62
|
try {
|
|
60
|
-
const memoryService = getDefaultMemoryService();
|
|
61
63
|
await memoryService.initialize();
|
|
62
64
|
|
|
63
65
|
const recentEvents = await memoryService.getRecentEvents(10000);
|
|
@@ -97,5 +99,7 @@ citationsRouter.get('/:id/related', async (c) => {
|
|
|
97
99
|
});
|
|
98
100
|
} catch (error) {
|
|
99
101
|
return c.json({ error: (error as Error).message }, 500);
|
|
102
|
+
} finally {
|
|
103
|
+
await memoryService.shutdown();
|
|
100
104
|
}
|
|
101
105
|
});
|
package/src/server/api/events.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Hono } from 'hono';
|
|
7
|
-
import {
|
|
7
|
+
import { getReadOnlyMemoryService } from '../../services/memory-service.js';
|
|
8
8
|
|
|
9
9
|
export const eventsRouter = new Hono();
|
|
10
10
|
|
|
@@ -14,9 +14,9 @@ eventsRouter.get('/', async (c) => {
|
|
|
14
14
|
const eventType = c.req.query('type');
|
|
15
15
|
const limit = parseInt(c.req.query('limit') || '100', 10);
|
|
16
16
|
const offset = parseInt(c.req.query('offset') || '0', 10);
|
|
17
|
+
const memoryService = getReadOnlyMemoryService();
|
|
17
18
|
|
|
18
19
|
try {
|
|
19
|
-
const memoryService = getDefaultMemoryService();
|
|
20
20
|
await memoryService.initialize();
|
|
21
21
|
|
|
22
22
|
let events = await memoryService.getRecentEvents(limit + offset + 1000);
|
|
@@ -51,15 +51,17 @@ eventsRouter.get('/', async (c) => {
|
|
|
51
51
|
});
|
|
52
52
|
} catch (error) {
|
|
53
53
|
return c.json({ error: (error as Error).message }, 500);
|
|
54
|
+
} finally {
|
|
55
|
+
await memoryService.shutdown();
|
|
54
56
|
}
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
// GET /api/events/:id - Get event details
|
|
58
60
|
eventsRouter.get('/:id', async (c) => {
|
|
59
61
|
const { id } = c.req.param();
|
|
62
|
+
const memoryService = getReadOnlyMemoryService();
|
|
60
63
|
|
|
61
64
|
try {
|
|
62
|
-
const memoryService = getDefaultMemoryService();
|
|
63
65
|
await memoryService.initialize();
|
|
64
66
|
|
|
65
67
|
const recentEvents = await memoryService.getRecentEvents(10000);
|
|
@@ -97,5 +99,7 @@ eventsRouter.get('/:id', async (c) => {
|
|
|
97
99
|
});
|
|
98
100
|
} catch (error) {
|
|
99
101
|
return c.json({ error: (error as Error).message }, 500);
|
|
102
|
+
} finally {
|
|
103
|
+
await memoryService.shutdown();
|
|
100
104
|
}
|
|
101
105
|
});
|
package/src/server/api/search.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Hono } from 'hono';
|
|
7
|
-
import {
|
|
7
|
+
import { getReadOnlyMemoryService } from '../../services/memory-service.js';
|
|
8
8
|
|
|
9
9
|
export const searchRouter = new Hono();
|
|
10
10
|
|
|
@@ -20,6 +20,7 @@ interface SearchRequest {
|
|
|
20
20
|
|
|
21
21
|
// POST /api/search - Search memories
|
|
22
22
|
searchRouter.post('/', async (c) => {
|
|
23
|
+
const memoryService = getReadOnlyMemoryService();
|
|
23
24
|
try {
|
|
24
25
|
const body = await c.req.json<SearchRequest>();
|
|
25
26
|
|
|
@@ -27,7 +28,6 @@ searchRouter.post('/', async (c) => {
|
|
|
27
28
|
return c.json({ error: 'Query is required' }, 400);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const memoryService = getDefaultMemoryService();
|
|
31
31
|
await memoryService.initialize();
|
|
32
32
|
|
|
33
33
|
const startTime = Date.now();
|
|
@@ -60,6 +60,8 @@ searchRouter.post('/', async (c) => {
|
|
|
60
60
|
});
|
|
61
61
|
} catch (error) {
|
|
62
62
|
return c.json({ error: (error as Error).message }, 500);
|
|
63
|
+
} finally {
|
|
64
|
+
await memoryService.shutdown();
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
@@ -72,9 +74,9 @@ searchRouter.get('/', async (c) => {
|
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
const topK = parseInt(c.req.query('topK') || '5', 10);
|
|
77
|
+
const memoryService = getReadOnlyMemoryService();
|
|
75
78
|
|
|
76
79
|
try {
|
|
77
|
-
const memoryService = getDefaultMemoryService();
|
|
78
80
|
await memoryService.initialize();
|
|
79
81
|
|
|
80
82
|
const result = await memoryService.retrieveMemories(query, { topK });
|
|
@@ -94,5 +96,7 @@ searchRouter.get('/', async (c) => {
|
|
|
94
96
|
});
|
|
95
97
|
} catch (error) {
|
|
96
98
|
return c.json({ error: (error as Error).message }, 500);
|
|
99
|
+
} finally {
|
|
100
|
+
await memoryService.shutdown();
|
|
97
101
|
}
|
|
98
102
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Hono } from 'hono';
|
|
7
|
-
import {
|
|
7
|
+
import { getReadOnlyMemoryService } from '../../services/memory-service.js';
|
|
8
8
|
|
|
9
9
|
export const sessionsRouter = new Hono();
|
|
10
10
|
|
|
@@ -12,9 +12,9 @@ export const sessionsRouter = new Hono();
|
|
|
12
12
|
sessionsRouter.get('/', async (c) => {
|
|
13
13
|
const page = parseInt(c.req.query('page') || '1', 10);
|
|
14
14
|
const pageSize = parseInt(c.req.query('pageSize') || '20', 10);
|
|
15
|
+
const memoryService = getReadOnlyMemoryService();
|
|
15
16
|
|
|
16
17
|
try {
|
|
17
|
-
const memoryService = getDefaultMemoryService();
|
|
18
18
|
await memoryService.initialize();
|
|
19
19
|
|
|
20
20
|
// Get recent events and extract sessions
|
|
@@ -65,15 +65,17 @@ sessionsRouter.get('/', async (c) => {
|
|
|
65
65
|
});
|
|
66
66
|
} catch (error) {
|
|
67
67
|
return c.json({ error: (error as Error).message }, 500);
|
|
68
|
+
} finally {
|
|
69
|
+
await memoryService.shutdown();
|
|
68
70
|
}
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
// GET /api/sessions/:id - Get session details
|
|
72
74
|
sessionsRouter.get('/:id', async (c) => {
|
|
73
75
|
const { id } = c.req.param();
|
|
76
|
+
const memoryService = getReadOnlyMemoryService();
|
|
74
77
|
|
|
75
78
|
try {
|
|
76
|
-
const memoryService = getDefaultMemoryService();
|
|
77
79
|
await memoryService.initialize();
|
|
78
80
|
|
|
79
81
|
const events = await memoryService.getSessionHistory(id);
|
|
@@ -107,5 +109,7 @@ sessionsRouter.get('/:id', async (c) => {
|
|
|
107
109
|
});
|
|
108
110
|
} catch (error) {
|
|
109
111
|
return c.json({ error: (error as Error).message }, 500);
|
|
112
|
+
} finally {
|
|
113
|
+
await memoryService.shutdown();
|
|
110
114
|
}
|
|
111
115
|
});
|