opencode-mem 2.7.4 → 2.7.6
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 +23 -9
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +99 -37
- package/dist/services/ai/providers/base-provider.d.ts +1 -0
- package/dist/services/ai/providers/base-provider.d.ts.map +1 -1
- package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
- package/dist/services/ai/providers/openai-chat-completion.js +11 -2
- package/dist/services/client.d.ts +27 -0
- package/dist/services/client.d.ts.map +1 -1
- package/dist/services/client.js +38 -0
- package/dist/services/sqlite/vector-search.d.ts +1 -0
- package/dist/services/sqlite/vector-search.d.ts.map +1 -1
- package/dist/services/sqlite/vector-search.js +13 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Add to your OpenCode configuration at `~/.config/opencode/opencode.json`:
|
|
|
28
28
|
|
|
29
29
|
```jsonc
|
|
30
30
|
{
|
|
31
|
-
"plugins": ["opencode-mem"]
|
|
31
|
+
"plugins": ["opencode-mem"],
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -37,10 +37,10 @@ The plugin downloads automatically on next startup. macOS users with Apple Silic
|
|
|
37
37
|
## Usage Examples
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
|
-
memory({ mode: "add", content: "Project uses microservices architecture" })
|
|
41
|
-
memory({ mode: "search", query: "architecture decisions" })
|
|
42
|
-
memory({ mode: "profile" })
|
|
43
|
-
memory({ mode: "list", limit: 10 })
|
|
40
|
+
memory({ mode: "add", content: "Project uses microservices architecture" });
|
|
41
|
+
memory({ mode: "search", query: "architecture decisions" });
|
|
42
|
+
memory({ mode: "profile" });
|
|
43
|
+
memory({ mode: "list", limit: 10 });
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Access the web interface at `http://127.0.0.1:4747` for visual memory browsing and management.
|
|
@@ -57,24 +57,38 @@ Configure at `~/.config/opencode/opencode-mem.jsonc`:
|
|
|
57
57
|
"embeddingModel": "Xenova/nomic-embed-text-v1",
|
|
58
58
|
"webServerEnabled": true,
|
|
59
59
|
"webServerPort": 4747,
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
"autoCaptureEnabled": true,
|
|
62
62
|
"autoCaptureLanguage": "auto",
|
|
63
63
|
"memoryProvider": "openai-chat",
|
|
64
64
|
"memoryModel": "gpt-4o-mini",
|
|
65
65
|
"memoryApiUrl": "https://api.openai.com/v1",
|
|
66
66
|
"memoryApiKey": "sk-...",
|
|
67
|
-
|
|
67
|
+
"memoryTemperature": 0.3,
|
|
68
|
+
|
|
68
69
|
"showAutoCaptureToasts": true,
|
|
69
70
|
"showUserProfileToasts": true,
|
|
70
71
|
"showErrorToasts": true,
|
|
71
|
-
|
|
72
|
+
|
|
72
73
|
"userProfileAnalysisInterval": 10,
|
|
73
|
-
"maxMemories": 10
|
|
74
|
+
"maxMemories": 10,
|
|
75
|
+
|
|
76
|
+
"compaction": {
|
|
77
|
+
"enabled": true,
|
|
78
|
+
"memoryLimit": 10,
|
|
79
|
+
},
|
|
80
|
+
"chatMessage": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"maxMemories": 3,
|
|
83
|
+
"excludeCurrentSession": true,
|
|
84
|
+
"maxAgeDays": undefined,
|
|
85
|
+
"injectOn": "first",
|
|
86
|
+
},
|
|
74
87
|
}
|
|
75
88
|
```
|
|
76
89
|
|
|
77
90
|
**API Key Formats:**
|
|
91
|
+
|
|
78
92
|
```jsonc
|
|
79
93
|
"memoryApiKey": "sk-..."
|
|
80
94
|
"memoryApiKey": "file://~/.config/opencode/api-key.txt"
|
package/dist/config.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare const CONFIG: {
|
|
|
20
20
|
memoryModel: string | undefined;
|
|
21
21
|
memoryApiUrl: string | undefined;
|
|
22
22
|
memoryApiKey: string | undefined;
|
|
23
|
+
memoryTemperature: number | false | undefined;
|
|
23
24
|
aiSessionRetentionDays: number;
|
|
24
25
|
webServerEnabled: boolean;
|
|
25
26
|
webServerPort: number;
|
|
@@ -38,6 +39,17 @@ export declare const CONFIG: {
|
|
|
38
39
|
showAutoCaptureToasts: boolean;
|
|
39
40
|
showUserProfileToasts: boolean;
|
|
40
41
|
showErrorToasts: boolean;
|
|
42
|
+
compaction: {
|
|
43
|
+
enabled: boolean | undefined;
|
|
44
|
+
memoryLimit: number | undefined;
|
|
45
|
+
};
|
|
46
|
+
chatMessage: {
|
|
47
|
+
enabled: boolean | undefined;
|
|
48
|
+
maxMemories: number | undefined;
|
|
49
|
+
excludeCurrentSession: boolean | undefined;
|
|
50
|
+
maxAgeDays: number | undefined;
|
|
51
|
+
injectOn: "first" | "always";
|
|
52
|
+
};
|
|
41
53
|
};
|
|
42
54
|
export declare function isConfigured(): boolean;
|
|
43
55
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA8ZA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;oBA2Bb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwCT,OAAO,GACP,QAAQ;;CAEf,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
package/dist/config.js
CHANGED
|
@@ -45,6 +45,17 @@ const DEFAULTS = {
|
|
|
45
45
|
showAutoCaptureToasts: true,
|
|
46
46
|
showUserProfileToasts: true,
|
|
47
47
|
showErrorToasts: true,
|
|
48
|
+
compaction: {
|
|
49
|
+
enabled: true,
|
|
50
|
+
memoryLimit: 10,
|
|
51
|
+
},
|
|
52
|
+
chatMessage: {
|
|
53
|
+
enabled: true,
|
|
54
|
+
maxMemories: 3,
|
|
55
|
+
excludeCurrentSession: true,
|
|
56
|
+
maxAgeDays: undefined,
|
|
57
|
+
injectOn: "first",
|
|
58
|
+
},
|
|
48
59
|
};
|
|
49
60
|
function expandPath(path) {
|
|
50
61
|
if (path.startsWith("~/")) {
|
|
@@ -198,13 +209,18 @@ const CONFIG_TEMPLATE = `{
|
|
|
198
209
|
|
|
199
210
|
// Maximum iterations for multi-turn AI analysis (for openai-responses and anthropic)
|
|
200
211
|
"autoCaptureMaxIterations": 5,
|
|
201
|
-
|
|
212
|
+
|
|
202
213
|
// Timeout per iteration in milliseconds (30 seconds default)
|
|
203
214
|
"autoCaptureIterationTimeout": 30000,
|
|
204
|
-
|
|
215
|
+
|
|
205
216
|
// Days to keep AI session history before cleanup
|
|
206
217
|
"aiSessionRetentionDays": 7,
|
|
207
218
|
|
|
219
|
+
// Temperature for AI API requests (set to false to omit parameter for models that don't support it)
|
|
220
|
+
// Some reasoning models (like o1, o3, gpt-5) don't support temperature parameter
|
|
221
|
+
// Set to false and add "memoryTemperature": false in config when using such models
|
|
222
|
+
"memoryTemperature": 0.3,
|
|
223
|
+
|
|
208
224
|
// Language for auto-capture summaries (default: "auto" for auto-detection)
|
|
209
225
|
// Options: "auto", "en", "id", "zh", "ja", "es", "fr", "de", "ru", "pt", "ar", "ko"
|
|
210
226
|
// "autoCaptureLanguage": "auto",
|
|
@@ -331,6 +347,7 @@ export const CONFIG = {
|
|
|
331
347
|
memoryModel: fileConfig.memoryModel,
|
|
332
348
|
memoryApiUrl: fileConfig.memoryApiUrl,
|
|
333
349
|
memoryApiKey: resolveSecretValue(fileConfig.memoryApiKey),
|
|
350
|
+
memoryTemperature: fileConfig.memoryTemperature,
|
|
334
351
|
aiSessionRetentionDays: fileConfig.aiSessionRetentionDays ?? DEFAULTS.aiSessionRetentionDays,
|
|
335
352
|
webServerEnabled: fileConfig.webServerEnabled ?? DEFAULTS.webServerEnabled,
|
|
336
353
|
webServerPort: fileConfig.webServerPort ?? DEFAULTS.webServerPort,
|
|
@@ -349,6 +366,17 @@ export const CONFIG = {
|
|
|
349
366
|
showAutoCaptureToasts: fileConfig.showAutoCaptureToasts ?? DEFAULTS.showAutoCaptureToasts,
|
|
350
367
|
showUserProfileToasts: fileConfig.showUserProfileToasts ?? DEFAULTS.showUserProfileToasts,
|
|
351
368
|
showErrorToasts: fileConfig.showErrorToasts ?? DEFAULTS.showErrorToasts,
|
|
369
|
+
compaction: {
|
|
370
|
+
enabled: fileConfig.compaction?.enabled ?? DEFAULTS.compaction.enabled,
|
|
371
|
+
memoryLimit: fileConfig.compaction?.memoryLimit ?? DEFAULTS.compaction.memoryLimit,
|
|
372
|
+
},
|
|
373
|
+
chatMessage: {
|
|
374
|
+
enabled: fileConfig.chatMessage?.enabled ?? DEFAULTS.chatMessage.enabled,
|
|
375
|
+
maxMemories: fileConfig.chatMessage?.maxMemories ?? DEFAULTS.chatMessage.maxMemories,
|
|
376
|
+
excludeCurrentSession: fileConfig.chatMessage?.excludeCurrentSession ?? DEFAULTS.chatMessage.excludeCurrentSession,
|
|
377
|
+
maxAgeDays: fileConfig.chatMessage?.maxAgeDays,
|
|
378
|
+
injectOn: (fileConfig.chatMessage?.injectOn ?? DEFAULTS.chatMessage.injectOn),
|
|
379
|
+
},
|
|
352
380
|
};
|
|
353
381
|
export function isConfigured() {
|
|
354
382
|
return true;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkB/D,eAAO,MAAM,iBAAiB,EAAE,MA+Z/B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -98,7 +98,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
98
98
|
process.on("SIGTERM", shutdownHandler);
|
|
99
99
|
return {
|
|
100
100
|
"chat.message": async (input, output) => {
|
|
101
|
-
if (!isConfigured())
|
|
101
|
+
if (!isConfigured() || !CONFIG.chatMessage.enabled)
|
|
102
102
|
return;
|
|
103
103
|
try {
|
|
104
104
|
const textParts = output.parts.filter((p) => p.type === "text");
|
|
@@ -108,42 +108,52 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
108
108
|
if (!userMessage.trim())
|
|
109
109
|
return;
|
|
110
110
|
userPromptManager.savePrompt(input.sessionID, output.message.id, directory, userMessage);
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
111
|
+
const messagesResponse = await ctx.client.session.messages({
|
|
112
|
+
path: { id: input.sessionID },
|
|
113
|
+
});
|
|
114
|
+
const messages = messagesResponse.data || [];
|
|
115
|
+
const hasNonSyntheticUserMessages = messages.some((m) => m.info.role === "user" &&
|
|
116
|
+
!m.parts.every((p) => p.type !== "text" || p.synthetic === true));
|
|
117
|
+
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;
|
|
118
|
+
const isAfterCompaction = lastMessage?.info?.summary === true;
|
|
119
|
+
const shouldInject = CONFIG.chatMessage.injectOn === "always" ||
|
|
120
|
+
!hasNonSyntheticUserMessages ||
|
|
121
|
+
(isAfterCompaction &&
|
|
122
|
+
messages.filter((m) => m.info.role === "user" &&
|
|
123
|
+
!m.parts.every((p) => p.type !== "text" || p.synthetic === true)).length === 1);
|
|
124
|
+
if (!shouldInject)
|
|
125
|
+
return;
|
|
126
|
+
const listResult = await memoryClient.listMemories(tags.project.tag, CONFIG.chatMessage.maxMemories);
|
|
127
|
+
let memories = listResult.success ? listResult.memories : [];
|
|
128
|
+
if (CONFIG.chatMessage.excludeCurrentSession) {
|
|
129
|
+
memories = memories.filter((m) => m.metadata?.sessionID !== input.sessionID);
|
|
130
|
+
}
|
|
131
|
+
if (CONFIG.chatMessage.maxAgeDays) {
|
|
132
|
+
const cutoffDate = Date.now() - CONFIG.chatMessage.maxAgeDays * 86400000;
|
|
133
|
+
memories = memories.filter((m) => new Date(m.createdAt).getTime() > cutoffDate);
|
|
134
|
+
}
|
|
135
|
+
if (memories.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
const projectMemories = {
|
|
138
|
+
results: memories.map((m) => ({
|
|
139
|
+
similarity: 1.0,
|
|
140
|
+
memory: m.summary,
|
|
141
|
+
})),
|
|
142
|
+
total: memories.length,
|
|
143
|
+
timing: 0,
|
|
144
|
+
};
|
|
145
|
+
const userId = tags.user.userEmail || null;
|
|
146
|
+
const memoryContext = formatContextForPrompt(userId, projectMemories);
|
|
147
|
+
if (memoryContext) {
|
|
148
|
+
const contextPart = {
|
|
149
|
+
id: `memory-context-${Date.now()}`,
|
|
150
|
+
sessionID: input.sessionID,
|
|
151
|
+
messageID: output.message.id,
|
|
152
|
+
type: "text",
|
|
153
|
+
text: memoryContext,
|
|
154
|
+
synthetic: true,
|
|
155
|
+
};
|
|
156
|
+
output.parts.unshift(contextPart);
|
|
147
157
|
}
|
|
148
158
|
}
|
|
149
159
|
catch (error) {
|
|
@@ -315,6 +325,47 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
315
325
|
}
|
|
316
326
|
}, 10000);
|
|
317
327
|
}
|
|
328
|
+
if (event.type === "session.compacted") {
|
|
329
|
+
if (!isConfigured() || !CONFIG.compaction.enabled)
|
|
330
|
+
return;
|
|
331
|
+
const sessionID = event.properties?.sessionID;
|
|
332
|
+
if (!sessionID)
|
|
333
|
+
return;
|
|
334
|
+
try {
|
|
335
|
+
const tags = getTags(directory);
|
|
336
|
+
const memoriesResult = await memoryClient.searchMemoriesBySessionID(sessionID, tags.project.tag, CONFIG.compaction.memoryLimit);
|
|
337
|
+
if (!memoriesResult.success || memoriesResult.results.length === 0) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const memoryContext = formatMemoriesForCompaction(memoriesResult.results);
|
|
341
|
+
await ctx.client.session.prompt({
|
|
342
|
+
path: { id: sessionID },
|
|
343
|
+
body: {
|
|
344
|
+
parts: [{ type: "text", text: memoryContext }],
|
|
345
|
+
noReply: true,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
if (ctx.client?.tui) {
|
|
349
|
+
await ctx.client.tui
|
|
350
|
+
.showToast({
|
|
351
|
+
body: {
|
|
352
|
+
title: "Memory Restored",
|
|
353
|
+
message: `${memoriesResult.results.length} memories injected after compaction`,
|
|
354
|
+
variant: "success",
|
|
355
|
+
duration: 3000,
|
|
356
|
+
},
|
|
357
|
+
})
|
|
358
|
+
.catch(() => { });
|
|
359
|
+
}
|
|
360
|
+
log("Compaction memory injected", {
|
|
361
|
+
sessionID,
|
|
362
|
+
count: memoriesResult.results.length,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
log("Compaction handler error", { error: String(error) });
|
|
367
|
+
}
|
|
368
|
+
}
|
|
318
369
|
},
|
|
319
370
|
};
|
|
320
371
|
};
|
|
@@ -331,3 +382,14 @@ function formatSearchResults(query, results, limit) {
|
|
|
331
382
|
})),
|
|
332
383
|
});
|
|
333
384
|
}
|
|
385
|
+
function formatMemoriesForCompaction(memories) {
|
|
386
|
+
let output = `## Restored Session Memory\n\n`;
|
|
387
|
+
memories.forEach((m, i) => {
|
|
388
|
+
output += `### Memory ${i + 1}\n`;
|
|
389
|
+
output += `${m.memory}\n\n`;
|
|
390
|
+
if (m.tags && m.tags.length > 0) {
|
|
391
|
+
output += `Tags: ${m.tags.join(", ")}\n\n`;
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
return output;
|
|
395
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-provider.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/base-provider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"base-provider.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/base-provider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACpC;AAED,8BAAsB,cAAc;IAClC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC;gBAErB,MAAM,EAAE,cAAc;IAIlC,QAAQ,CAAC,eAAe,CACtB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,GAAG,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAE1B,QAAQ,CAAC,eAAe,IAAI,MAAM;IAElC,QAAQ,CAAC,eAAe,IAAI,OAAO;CACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAqBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAI1B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,iCAAiC;IAoCnC,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"openai-chat-completion.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-chat-completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAqBlE,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAI1B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,iCAAiC;IAoCnC,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;CAwP3B"}
|
|
@@ -116,8 +116,10 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
116
116
|
messages,
|
|
117
117
|
tools: [toolSchema],
|
|
118
118
|
tool_choice: { type: "function", function: { name: toolSchema.function.name } },
|
|
119
|
-
temperature: 0.3,
|
|
120
119
|
};
|
|
120
|
+
if (this.config.memoryTemperature !== false) {
|
|
121
|
+
requestBody.temperature = this.config.memoryTemperature ?? 0.3;
|
|
122
|
+
}
|
|
121
123
|
const headers = {
|
|
122
124
|
"Content-Type": "application/json",
|
|
123
125
|
};
|
|
@@ -138,9 +140,16 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
138
140
|
error: errorText,
|
|
139
141
|
iteration: iterations,
|
|
140
142
|
});
|
|
143
|
+
let errorMessage = `API error: ${response.status} - ${errorText}`;
|
|
144
|
+
if (response.status === 400 &&
|
|
145
|
+
errorText.includes("unsupported_value") &&
|
|
146
|
+
errorText.includes("temperature")) {
|
|
147
|
+
errorMessage =
|
|
148
|
+
'Your model does not support the temperature parameter. Add "memoryTemperature": false to your config file to disable it.';
|
|
149
|
+
}
|
|
141
150
|
return {
|
|
142
151
|
success: false,
|
|
143
|
-
error:
|
|
152
|
+
error: errorMessage,
|
|
144
153
|
iterations,
|
|
145
154
|
};
|
|
146
155
|
}
|
|
@@ -86,6 +86,33 @@ export declare class LocalMemoryClient {
|
|
|
86
86
|
totalPages: number;
|
|
87
87
|
};
|
|
88
88
|
}>;
|
|
89
|
+
searchMemoriesBySessionID(sessionID: string, containerTag: string, limit?: number): Promise<{
|
|
90
|
+
success: true;
|
|
91
|
+
results: {
|
|
92
|
+
id: any;
|
|
93
|
+
memory: any;
|
|
94
|
+
similarity: number;
|
|
95
|
+
tags: any;
|
|
96
|
+
metadata: any;
|
|
97
|
+
containerTag: any;
|
|
98
|
+
displayName: any;
|
|
99
|
+
userName: any;
|
|
100
|
+
userEmail: any;
|
|
101
|
+
projectPath: any;
|
|
102
|
+
projectName: any;
|
|
103
|
+
gitRepoUrl: any;
|
|
104
|
+
createdAt: any;
|
|
105
|
+
}[];
|
|
106
|
+
total: number;
|
|
107
|
+
timing: number;
|
|
108
|
+
error?: undefined;
|
|
109
|
+
} | {
|
|
110
|
+
success: false;
|
|
111
|
+
error: string;
|
|
112
|
+
results: never[];
|
|
113
|
+
total: number;
|
|
114
|
+
timing: number;
|
|
115
|
+
}>;
|
|
89
116
|
}
|
|
90
117
|
export declare const memoryClient: LocalMemoryClient;
|
|
91
118
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuD7C,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C5F;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
|
package/dist/services/client.js
CHANGED
|
@@ -209,5 +209,43 @@ export class LocalMemoryClient {
|
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
|
+
async searchMemoriesBySessionID(sessionID, containerTag, limit = 10) {
|
|
213
|
+
try {
|
|
214
|
+
await this.initialize();
|
|
215
|
+
const { scope, hash } = extractScopeFromContainerTag(containerTag);
|
|
216
|
+
const shards = shardManager.getAllShards(scope, hash);
|
|
217
|
+
if (shards.length === 0) {
|
|
218
|
+
return { success: true, results: [], total: 0, timing: 0 };
|
|
219
|
+
}
|
|
220
|
+
const allMemories = [];
|
|
221
|
+
for (const shard of shards) {
|
|
222
|
+
const db = connectionManager.getConnection(shard.dbPath);
|
|
223
|
+
const memories = vectorSearch.getMemoriesBySessionID(db, sessionID);
|
|
224
|
+
allMemories.push(...memories);
|
|
225
|
+
}
|
|
226
|
+
allMemories.sort((a, b) => b.created_at - a.created_at);
|
|
227
|
+
const results = allMemories.slice(0, limit).map((row) => ({
|
|
228
|
+
id: row.id,
|
|
229
|
+
memory: row.content,
|
|
230
|
+
similarity: 1.0,
|
|
231
|
+
tags: row.tags || [],
|
|
232
|
+
metadata: row.metadata || {},
|
|
233
|
+
containerTag: row.container_tag,
|
|
234
|
+
displayName: row.display_name,
|
|
235
|
+
userName: row.user_name,
|
|
236
|
+
userEmail: row.user_email,
|
|
237
|
+
projectPath: row.project_path,
|
|
238
|
+
projectName: row.project_name,
|
|
239
|
+
gitRepoUrl: row.git_repo_url,
|
|
240
|
+
createdAt: row.created_at,
|
|
241
|
+
}));
|
|
242
|
+
return { success: true, results, total: results.length, timing: 0 };
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
246
|
+
log("searchMemoriesBySessionID: error", { error: errorMessage });
|
|
247
|
+
return { success: false, error: errorMessage, results: [], total: 0, timing: 0 };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
212
250
|
}
|
|
213
251
|
export const memoryClient = new LocalMemoryClient();
|
|
@@ -9,6 +9,7 @@ export declare class VectorSearch {
|
|
|
9
9
|
listMemories(db: Database, containerTag: string, limit: number): any[];
|
|
10
10
|
getAllMemories(db: Database): any[];
|
|
11
11
|
getMemoryById(db: Database, memoryId: string): any | null;
|
|
12
|
+
getMemoriesBySessionID(db: Database, sessionID: string): any[];
|
|
12
13
|
countVectors(db: Database, containerTag: string): number;
|
|
13
14
|
countAllVectors(db: Database): number;
|
|
14
15
|
getDistinctTags(db: Database): any[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-search.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/vector-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,YAAY;IACvB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IA0CtD,aAAa,CACX,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,YAAY,EAAE;IA0FX,kBAAkB,CACtB,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,EAC3B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC;IAiB1B,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlD,YAAY,
|
|
1
|
+
{"version":3,"file":"vector-search.d.ts","sourceRoot":"","sources":["../../../src/services/sqlite/vector-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,YAAY;IACvB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IA0CtD,aAAa,CACX,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,YAAY,EAAE;IA0FX,kBAAkB,CACtB,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,EAC3B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC;IAiB1B,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlD,YAAY,CACV,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,UAAU,CAAC,EAAE,YAAY,GACxB,IAAI;IAkBP,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE;IAWtE,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAKnC,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAKzD,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,EAAE;IAgB9D,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAMxD,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM;IAMrC,eAAe,CAAC,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;IAepC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK/C,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAIlD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -140,6 +140,19 @@ export class VectorSearch {
|
|
|
140
140
|
const stmt = db.prepare(`SELECT * FROM memories WHERE id = ?`);
|
|
141
141
|
return stmt.get(memoryId);
|
|
142
142
|
}
|
|
143
|
+
getMemoriesBySessionID(db, sessionID) {
|
|
144
|
+
const stmt = db.prepare(`
|
|
145
|
+
SELECT * FROM memories
|
|
146
|
+
WHERE metadata LIKE ?
|
|
147
|
+
ORDER BY created_at DESC
|
|
148
|
+
`);
|
|
149
|
+
const rows = stmt.all(`%"sessionID":"${sessionID}"%`);
|
|
150
|
+
return rows.map((row) => ({
|
|
151
|
+
...row,
|
|
152
|
+
tags: row.tags ? row.tags.split(",") : [],
|
|
153
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : {},
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
143
156
|
countVectors(db, containerTag) {
|
|
144
157
|
const stmt = db.prepare(`SELECT COUNT(*) as count FROM memories WHERE container_tag = ?`);
|
|
145
158
|
const result = stmt.get(containerTag);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-mem",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.6",
|
|
4
4
|
"description": "OpenCode plugin that gives coding agents persistent memory using local vector database",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@xenova/transformers": "^2.17.2",
|
|
38
38
|
"franc-min": "^6.2.0",
|
|
39
39
|
"iso-639-3": "^3.0.1",
|
|
40
|
-
"sqlite-vec": "
|
|
40
|
+
"sqlite-vec": "0.1.7-alpha.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/bun": "^1.3.8",
|