opencode-mem 2.1.1 → 2.3.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 +60 -77
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -86
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +0 -4
- package/dist/services/ai/providers/anthropic-messages.d.ts.map +1 -1
- package/dist/services/ai/providers/anthropic-messages.js +11 -17
- package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
- package/dist/services/ai/providers/openai-chat-completion.js +11 -17
- package/dist/services/ai/providers/openai-responses.d.ts.map +1 -1
- package/dist/services/ai/providers/openai-responses.js +11 -17
- package/dist/services/api-handlers.d.ts +5 -3
- package/dist/services/api-handlers.d.ts.map +1 -1
- package/dist/services/api-handlers.js +165 -42
- package/dist/services/auto-capture.js +2 -2
- package/dist/services/context.d.ts +1 -1
- package/dist/services/context.d.ts.map +1 -1
- package/dist/services/context.js +1 -10
- package/dist/services/deduplication-service.d.ts.map +1 -1
- package/dist/services/deduplication-service.js +1 -3
- package/dist/services/logger.js +1 -1
- package/dist/services/user-memory-learning.d.ts +1 -1
- package/dist/services/user-memory-learning.d.ts.map +1 -1
- package/dist/services/user-memory-learning.js +5 -3
- package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -1
- package/dist/services/web-server-worker.js +30 -3
- package/dist/web/app.js +254 -47
- package/dist/web/index.html +31 -15
- package/dist/web/styles.css +309 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,9 @@ OpenCode Memory provides AI coding agents with the ability to remember and recal
|
|
|
11
11
|
## Key Features
|
|
12
12
|
|
|
13
13
|
- **Local Vector Database**: SQLite-based storage with sqlite-vec extension
|
|
14
|
-
- **
|
|
14
|
+
- **Project Memory System**: Persistent storage for project-specific knowledge
|
|
15
|
+
- **User Profile System**: Automatic learning of preferences, patterns, and workflows
|
|
15
16
|
- **Unified Timeline**: Browse memories and prompts together with linking support
|
|
16
|
-
- **Prompt-Memory Linking**: Bidirectional links between prompts and generated memories
|
|
17
|
-
- **User Learning System**: Analyzes user patterns and preferences from conversation history
|
|
18
17
|
- **Web Interface**: Full-featured UI for memory management and search
|
|
19
18
|
- **Auto-Capture System**: Intelligent prompt-based memory extraction
|
|
20
19
|
- **Multi-Provider AI**: Support for OpenAI, Anthropic, and OpenAI-compatible APIs
|
|
@@ -52,16 +51,32 @@ bun run build
|
|
|
52
51
|
### Basic Usage
|
|
53
52
|
|
|
54
53
|
```typescript
|
|
55
|
-
|
|
56
|
-
memory({ mode: "
|
|
54
|
+
// Add project memory
|
|
55
|
+
memory({ mode: "add", content: "Project uses microservices architecture" })
|
|
56
|
+
|
|
57
|
+
// Search memories
|
|
58
|
+
memory({ mode: "search", query: "architecture decisions" })
|
|
59
|
+
|
|
60
|
+
// View user profile
|
|
57
61
|
memory({ mode: "profile" })
|
|
62
|
+
|
|
63
|
+
// List recent memories
|
|
64
|
+
memory({ mode: "list", limit: 10 })
|
|
58
65
|
```
|
|
59
66
|
|
|
60
67
|
### Web Interface
|
|
61
68
|
|
|
62
69
|
Access at `http://127.0.0.1:4747` to browse memories, view prompt-memory links, and manage your memory database.
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
**Project Memory Timeline:**
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
**User Profile Viewer:**
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
65
80
|
|
|
66
81
|
Configuration file: `~/.config/opencode/opencode-mem.jsonc`
|
|
67
82
|
|
|
@@ -75,21 +90,49 @@ Configuration file: `~/.config/opencode/opencode-mem.jsonc`
|
|
|
75
90
|
"memoryProvider": "openai-chat",
|
|
76
91
|
"memoryModel": "gpt-4",
|
|
77
92
|
"memoryApiUrl": "https://api.openai.com/v1",
|
|
78
|
-
"memoryApiKey": "sk-..."
|
|
93
|
+
"memoryApiKey": "sk-...",
|
|
94
|
+
"userProfileAnalysisInterval": 10,
|
|
95
|
+
"maxMemories": 10
|
|
79
96
|
}
|
|
80
97
|
```
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
See [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide) for all options.
|
|
100
|
+
|
|
101
|
+
## Breaking Changes (v2.3)
|
|
102
|
+
|
|
103
|
+
**User-scoped memories completely removed:**
|
|
104
|
+
|
|
105
|
+
- **Removed**: `scope` parameter from all memory operations
|
|
106
|
+
- **Removed**: `maxProjectMemories` config (use `maxMemories` instead)
|
|
107
|
+
- **Renamed**: `userMemoryAnalysisInterval` → `userProfileAnalysisInterval`
|
|
108
|
+
- **Renamed**: `performUserMemoryLearning()` → `performUserProfileLearning()`
|
|
109
|
+
- **Changed**: All memories are now project-scoped by default
|
|
110
|
+
- **Changed**: User preferences managed exclusively through automatic profile system
|
|
83
111
|
|
|
84
|
-
**
|
|
112
|
+
**Migration required:**
|
|
113
|
+
```jsonc
|
|
114
|
+
// OLD
|
|
115
|
+
{
|
|
116
|
+
"userMemoryAnalysisInterval": 10,
|
|
117
|
+
"maxMemories": 5,
|
|
118
|
+
"maxProjectMemories": 10
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// NEW
|
|
122
|
+
{
|
|
123
|
+
"userProfileAnalysisInterval": 10,
|
|
124
|
+
"maxMemories": 10
|
|
125
|
+
}
|
|
126
|
+
```
|
|
85
127
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- Prompt-memory linking with cascade delete support
|
|
128
|
+
Remove `scope` parameter from all `memory()` calls:
|
|
129
|
+
```typescript
|
|
130
|
+
// OLD
|
|
131
|
+
memory({ mode: "add", content: "...", scope: "project" })
|
|
91
132
|
|
|
92
|
-
|
|
133
|
+
// NEW
|
|
134
|
+
memory({ mode: "add", content: "..." })
|
|
135
|
+
```
|
|
93
136
|
|
|
94
137
|
## Documentation
|
|
95
138
|
|
|
@@ -98,73 +141,13 @@ For detailed documentation, see the [Wiki](https://github.com/tickernelz/opencod
|
|
|
98
141
|
- [Installation Guide](https://github.com/tickernelz/opencode-mem/wiki/Installation-Guide)
|
|
99
142
|
- [Quick Start](https://github.com/tickernelz/opencode-mem/wiki/Quick-Start)
|
|
100
143
|
- [Configuration Guide](https://github.com/tickernelz/opencode-mem/wiki/Configuration-Guide)
|
|
144
|
+
- [User Profile System](https://github.com/tickernelz/opencode-mem/wiki/User-Profile-System)
|
|
101
145
|
- [Memory Operations](https://github.com/tickernelz/opencode-mem/wiki/Memory-Operations)
|
|
102
146
|
- [Auto-Capture System](https://github.com/tickernelz/opencode-mem/wiki/Auto-Capture-System)
|
|
103
147
|
- [Web Interface](https://github.com/tickernelz/opencode-mem/wiki/Web-Interface)
|
|
104
|
-
- [
|
|
105
|
-
- [Performance Tuning](https://github.com/tickernelz/opencode-mem/wiki/Performance-Tuning)
|
|
148
|
+
- [API Reference](https://github.com/tickernelz/opencode-mem/wiki/API-Reference)
|
|
106
149
|
- [Troubleshooting](https://github.com/tickernelz/opencode-mem/wiki/Troubleshooting)
|
|
107
150
|
|
|
108
|
-
## Features Overview
|
|
109
|
-
|
|
110
|
-
### Memory Scopes
|
|
111
|
-
|
|
112
|
-
- **User Scope**: Cross-project preferences, coding style, communication patterns
|
|
113
|
-
- **Project Scope**: Architecture decisions, technology stack, implementation details
|
|
114
|
-
|
|
115
|
-
### Auto-Capture System
|
|
116
|
-
|
|
117
|
-
Automatically extracts memories from conversations:
|
|
118
|
-
|
|
119
|
-
1. Triggers on session idle
|
|
120
|
-
2. Analyzes last uncaptured prompt and response
|
|
121
|
-
3. Links memory to source prompt
|
|
122
|
-
4. Skips non-technical conversations
|
|
123
|
-
|
|
124
|
-
### User Learning System
|
|
125
|
-
|
|
126
|
-
Analyzes batches of prompts to identify patterns (default: every 10 prompts):
|
|
127
|
-
|
|
128
|
-
- Coding style preferences
|
|
129
|
-
- Communication patterns
|
|
130
|
-
- Tool preferences
|
|
131
|
-
- Skill level indicators
|
|
132
|
-
|
|
133
|
-
### Web Interface
|
|
134
|
-
|
|
135
|
-
- Unified timeline of memories and prompts
|
|
136
|
-
- Visual prompt-memory link indicators
|
|
137
|
-
- Cascade delete for linked items
|
|
138
|
-
- Bulk operations
|
|
139
|
-
- Search and filters
|
|
140
|
-
- Maintenance tools (cleanup, deduplication)
|
|
141
|
-
|
|
142
|
-
## API Reference
|
|
143
|
-
|
|
144
|
-
### Memory Tool
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
memory({ mode: "add", content: "...", scope: "user|project" })
|
|
148
|
-
memory({ mode: "search", query: "...", scope: "user|project" })
|
|
149
|
-
memory({ mode: "list", scope: "user|project", limit: 10 })
|
|
150
|
-
memory({ mode: "profile" })
|
|
151
|
-
memory({ mode: "forget", memoryId: "..." })
|
|
152
|
-
memory({ mode: "auto-capture-toggle" })
|
|
153
|
-
memory({ mode: "auto-capture-stats" })
|
|
154
|
-
memory({ mode: "capture-now" })
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### REST API
|
|
158
|
-
|
|
159
|
-
- `GET /api/memories?scope=project&includePrompts=true` - List memories/prompts
|
|
160
|
-
- `POST /api/memories` - Create memory
|
|
161
|
-
- `PUT /api/memories/:id` - Update memory
|
|
162
|
-
- `DELETE /api/memories/:id?cascade=true` - Delete memory (and linked prompt)
|
|
163
|
-
- `DELETE /api/prompts/:id?cascade=true` - Delete prompt (and linked memory)
|
|
164
|
-
- `POST /api/search` - Vector search
|
|
165
|
-
- `POST /api/cleanup` - Run cleanup
|
|
166
|
-
- `POST /api/deduplicate` - Run deduplication
|
|
167
|
-
|
|
168
151
|
## Development
|
|
169
152
|
|
|
170
153
|
```bash
|
package/dist/config.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ export declare const CONFIG: {
|
|
|
6
6
|
embeddingApiKey: string | undefined;
|
|
7
7
|
similarityThreshold: number;
|
|
8
8
|
maxMemories: number;
|
|
9
|
-
maxProjectMemories: number;
|
|
10
9
|
maxProfileItems: number;
|
|
11
10
|
injectProfile: boolean;
|
|
12
11
|
containerTagPrefix: string;
|
|
@@ -27,7 +26,7 @@ export declare const CONFIG: {
|
|
|
27
26
|
autoCleanupRetentionDays: number;
|
|
28
27
|
deduplicationEnabled: boolean;
|
|
29
28
|
deduplicationSimilarityThreshold: number;
|
|
30
|
-
|
|
29
|
+
userProfileAnalysisInterval: number;
|
|
31
30
|
userProfileMaxPreferences: number;
|
|
32
31
|
userProfileMaxPatterns: number;
|
|
33
32
|
userProfileMaxWorkflows: number;
|
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":"AAsWA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;oBAuBb,aAAa,GACb,kBAAkB,GAClB,WAAW;;;;;;;;;;;;;;;;;;;CAyBhB,CAAC;AAEF,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
package/dist/config.js
CHANGED
|
@@ -37,8 +37,7 @@ const DEFAULTS = {
|
|
|
37
37
|
embeddingModel: "Xenova/nomic-embed-text-v1",
|
|
38
38
|
embeddingDimensions: 768,
|
|
39
39
|
similarityThreshold: 0.6,
|
|
40
|
-
maxMemories:
|
|
41
|
-
maxProjectMemories: 10,
|
|
40
|
+
maxMemories: 10,
|
|
42
41
|
maxProfileItems: 5,
|
|
43
42
|
injectProfile: true,
|
|
44
43
|
containerTagPrefix: "opencode",
|
|
@@ -55,7 +54,7 @@ const DEFAULTS = {
|
|
|
55
54
|
autoCleanupRetentionDays: 30,
|
|
56
55
|
deduplicationEnabled: true,
|
|
57
56
|
deduplicationSimilarityThreshold: 0.9,
|
|
58
|
-
|
|
57
|
+
userProfileAnalysisInterval: 10,
|
|
59
58
|
userProfileMaxPreferences: 20,
|
|
60
59
|
userProfileMaxPatterns: 15,
|
|
61
60
|
userProfileMaxWorkflows: 10,
|
|
@@ -205,18 +204,18 @@ const CONFIG_TEMPLATE = `{
|
|
|
205
204
|
|
|
206
205
|
// Days to keep AI session history before cleanup
|
|
207
206
|
"aiSessionRetentionDays": 7,
|
|
208
|
-
|
|
207
|
+
|
|
209
208
|
// ============================================
|
|
210
|
-
// User
|
|
209
|
+
// User Profile System
|
|
211
210
|
// ============================================
|
|
212
|
-
|
|
211
|
+
|
|
213
212
|
// Analyze user prompts every N prompts to build/update your user profile
|
|
214
213
|
// When N uncaptured prompts accumulate, AI will analyze them to identify:
|
|
215
214
|
// - User preferences (code style, communication style, tool preferences)
|
|
216
215
|
// - User patterns (recurring topics, problem domains, technical interests)
|
|
217
216
|
// - User workflows (development habits, sequences, learning style)
|
|
218
217
|
// - Skill level (overall and per-domain assessment)
|
|
219
|
-
"
|
|
218
|
+
"userProfileAnalysisInterval": 10,
|
|
220
219
|
|
|
221
220
|
// Maximum number of preferences to keep in user profile (sorted by confidence)
|
|
222
221
|
// Preferences are things like "prefers code without comments", "likes concise responses"
|
|
@@ -244,13 +243,10 @@ const CONFIG_TEMPLATE = `{
|
|
|
244
243
|
|
|
245
244
|
// Minimum similarity score (0-1) for memory search results
|
|
246
245
|
"similarityThreshold": 0.6,
|
|
247
|
-
|
|
248
|
-
// Maximum number of
|
|
249
|
-
"maxMemories":
|
|
250
|
-
|
|
251
|
-
// Maximum number of project-scoped memories to return in search
|
|
252
|
-
"maxProjectMemories": 10,
|
|
253
|
-
|
|
246
|
+
|
|
247
|
+
// Maximum number of memories to return in search results
|
|
248
|
+
"maxMemories": 10,
|
|
249
|
+
|
|
254
250
|
// ============================================
|
|
255
251
|
// Advanced Settings
|
|
256
252
|
// ============================================
|
|
@@ -304,7 +300,6 @@ export const CONFIG = {
|
|
|
304
300
|
embeddingApiKey: fileConfig.embeddingApiKey ?? process.env.OPENAI_API_KEY,
|
|
305
301
|
similarityThreshold: fileConfig.similarityThreshold ?? DEFAULTS.similarityThreshold,
|
|
306
302
|
maxMemories: fileConfig.maxMemories ?? DEFAULTS.maxMemories,
|
|
307
|
-
maxProjectMemories: fileConfig.maxProjectMemories ?? DEFAULTS.maxProjectMemories,
|
|
308
303
|
maxProfileItems: fileConfig.maxProfileItems ?? DEFAULTS.maxProfileItems,
|
|
309
304
|
injectProfile: fileConfig.injectProfile ?? DEFAULTS.injectProfile,
|
|
310
305
|
containerTagPrefix: fileConfig.containerTagPrefix ?? DEFAULTS.containerTagPrefix,
|
|
@@ -328,7 +323,7 @@ export const CONFIG = {
|
|
|
328
323
|
autoCleanupRetentionDays: fileConfig.autoCleanupRetentionDays ?? DEFAULTS.autoCleanupRetentionDays,
|
|
329
324
|
deduplicationEnabled: fileConfig.deduplicationEnabled ?? DEFAULTS.deduplicationEnabled,
|
|
330
325
|
deduplicationSimilarityThreshold: fileConfig.deduplicationSimilarityThreshold ?? DEFAULTS.deduplicationSimilarityThreshold,
|
|
331
|
-
|
|
326
|
+
userProfileAnalysisInterval: fileConfig.userProfileAnalysisInterval ?? DEFAULTS.userProfileAnalysisInterval,
|
|
332
327
|
userProfileMaxPreferences: fileConfig.userProfileMaxPreferences ?? DEFAULTS.userProfileMaxPreferences,
|
|
333
328
|
userProfileMaxPatterns: fileConfig.userProfileMaxPatterns ?? DEFAULTS.userProfileMaxPatterns,
|
|
334
329
|
userProfileMaxWorkflows: fileConfig.userProfileMaxWorkflows ?? DEFAULTS.userProfileMaxWorkflows,
|
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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA0C/D,eAAO,MAAM,iBAAiB,EAAE,MAyhB/B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { formatContextForPrompt } from "./services/context.js";
|
|
|
4
4
|
import { getTags } from "./services/tags.js";
|
|
5
5
|
import { stripPrivateContent, isFullyPrivate } from "./services/privacy.js";
|
|
6
6
|
import { performAutoCapture } from "./services/auto-capture.js";
|
|
7
|
-
import {
|
|
7
|
+
import { performUserProfileLearning } from "./services/user-memory-learning.js";
|
|
8
8
|
import { userPromptManager } from "./services/user-prompt/user-prompt-manager.js";
|
|
9
9
|
import { startWebServer, WebServer } from "./services/web-server.js";
|
|
10
10
|
import { isConfigured, CONFIG } from "./config.js";
|
|
@@ -16,10 +16,11 @@ const MEMORY_NUDGE_MESSAGE = `[MEMORY TRIGGER DETECTED]
|
|
|
16
16
|
The user wants you to remember something. You MUST use the \`memory\` tool with \`mode: "add"\` to save this information.
|
|
17
17
|
|
|
18
18
|
Extract the key information the user wants remembered and save it as a concise, searchable memory.
|
|
19
|
-
- Use \`scope: "project"\` for project-specific
|
|
20
|
-
- Use \`scope: "user"\` for cross-project preferences (e.g., "prefers concise responses")
|
|
19
|
+
- Use \`scope: "project"\` for project-specific knowledge (e.g., "run lint with tests", architecture decisions)
|
|
21
20
|
- Choose an appropriate \`type\`: "preference", "project-config", "learned-pattern", etc.
|
|
22
21
|
|
|
22
|
+
Note: User preferences are automatically learned through the user profile system. Only store project-specific information.
|
|
23
|
+
|
|
23
24
|
DO NOT skip this step. The user explicitly asked you to remember.`;
|
|
24
25
|
function removeCodeBlocks(text) {
|
|
25
26
|
return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "");
|
|
@@ -109,7 +110,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
109
110
|
"chat.message": async (input, output) => {
|
|
110
111
|
if (!isConfigured())
|
|
111
112
|
return;
|
|
112
|
-
const start = Date.now();
|
|
113
113
|
try {
|
|
114
114
|
const textParts = output.parts.filter((p) => p.type === "text");
|
|
115
115
|
if (textParts.length === 0)
|
|
@@ -184,11 +184,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
-
const
|
|
188
|
-
memoryClient.searchMemories(userMessage, tags.user.tag),
|
|
189
|
-
memoryClient.listMemories(tags.project.tag, CONFIG.maxProjectMemories),
|
|
190
|
-
]);
|
|
191
|
-
const userMemories = userMemoriesResult.success ? userMemoriesResult : { results: [] };
|
|
187
|
+
const projectMemoriesListResult = await memoryClient.listMemories(tags.project.tag, CONFIG.maxMemories);
|
|
192
188
|
const projectMemoriesList = projectMemoriesListResult.success
|
|
193
189
|
? projectMemoriesListResult
|
|
194
190
|
: { memories: [] };
|
|
@@ -204,7 +200,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
204
200
|
timing: 0,
|
|
205
201
|
};
|
|
206
202
|
const userId = tags.user.userEmail || null;
|
|
207
|
-
const memoryContext = formatContextForPrompt(userId,
|
|
203
|
+
const memoryContext = formatContextForPrompt(userId, projectMemories);
|
|
208
204
|
if (memoryContext) {
|
|
209
205
|
const contextPart = {
|
|
210
206
|
id: `memory-context-${Date.now()}`,
|
|
@@ -244,7 +240,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
244
240
|
content: tool.schema.string().optional(),
|
|
245
241
|
query: tool.schema.string().optional(),
|
|
246
242
|
type: tool.schema.string().optional(),
|
|
247
|
-
scope: tool.schema.enum(["user", "project"]).optional(),
|
|
248
243
|
memoryId: tool.schema.string().optional(),
|
|
249
244
|
limit: tool.schema.number().optional(),
|
|
250
245
|
},
|
|
@@ -272,28 +267,28 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
272
267
|
commands: [
|
|
273
268
|
{
|
|
274
269
|
command: "add",
|
|
275
|
-
description: "Store a new memory",
|
|
276
|
-
args: ["content", "type?"
|
|
270
|
+
description: "Store a new project memory",
|
|
271
|
+
args: ["content", "type?"],
|
|
277
272
|
},
|
|
278
273
|
{
|
|
279
274
|
command: "search",
|
|
280
|
-
description: "Search memories",
|
|
281
|
-
args: ["query"
|
|
275
|
+
description: "Search project memories",
|
|
276
|
+
args: ["query"],
|
|
282
277
|
},
|
|
283
278
|
{
|
|
284
279
|
command: "profile",
|
|
285
|
-
description: "View user profile",
|
|
286
|
-
args: [
|
|
280
|
+
description: "View user profile (preferences, patterns, workflows)",
|
|
281
|
+
args: [],
|
|
287
282
|
},
|
|
288
283
|
{
|
|
289
284
|
command: "list",
|
|
290
|
-
description: "List recent memories",
|
|
291
|
-
args: ["
|
|
285
|
+
description: "List recent project memories",
|
|
286
|
+
args: ["limit?"],
|
|
292
287
|
},
|
|
293
288
|
{
|
|
294
289
|
command: "forget",
|
|
295
|
-
description: "Remove a memory",
|
|
296
|
-
args: ["memoryId"
|
|
290
|
+
description: "Remove a project memory",
|
|
291
|
+
args: ["memoryId"],
|
|
297
292
|
},
|
|
298
293
|
{
|
|
299
294
|
command: "capture-now",
|
|
@@ -301,10 +296,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
301
296
|
args: [],
|
|
302
297
|
},
|
|
303
298
|
],
|
|
304
|
-
|
|
305
|
-
user: "Cross-project user behaviors, preferences, patterns, requests",
|
|
306
|
-
project: "Project-specific knowledge, decisions, architecture, context",
|
|
307
|
-
},
|
|
299
|
+
note: "User preferences are automatically learned through the user profile system. Only project-specific memories can be added manually.",
|
|
308
300
|
typeGuidance: "Choose appropriate type: preference, architecture, workflow, bug-fix, configuration, pattern, request, context, etc. Be specific and descriptive with categories.",
|
|
309
301
|
});
|
|
310
302
|
}
|
|
@@ -322,8 +314,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
322
314
|
error: "Cannot store fully private content",
|
|
323
315
|
});
|
|
324
316
|
}
|
|
325
|
-
const
|
|
326
|
-
const tagInfo = scope === "user" ? tags.user : tags.project;
|
|
317
|
+
const tagInfo = tags.project;
|
|
327
318
|
const result = await memoryClient.addMemory(sanitizedContent, tagInfo.tag, {
|
|
328
319
|
type: args.type,
|
|
329
320
|
displayName: tagInfo.displayName,
|
|
@@ -341,9 +332,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
341
332
|
}
|
|
342
333
|
return JSON.stringify({
|
|
343
334
|
success: true,
|
|
344
|
-
message: `Memory added to
|
|
335
|
+
message: `Memory added to project`,
|
|
345
336
|
id: result.id,
|
|
346
|
-
scope,
|
|
347
337
|
type: args.type,
|
|
348
338
|
});
|
|
349
339
|
}
|
|
@@ -354,58 +344,14 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
354
344
|
error: "query parameter is required for search mode",
|
|
355
345
|
});
|
|
356
346
|
}
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
359
|
-
const result = await memoryClient.searchMemories(args.query, tags.user.tag);
|
|
360
|
-
if (!result.success) {
|
|
361
|
-
return JSON.stringify({
|
|
362
|
-
success: false,
|
|
363
|
-
error: result.error || "Failed to search memories",
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
return formatSearchResults(args.query, scope, result, args.limit);
|
|
367
|
-
}
|
|
368
|
-
if (scope === "project") {
|
|
369
|
-
const result = await memoryClient.searchMemories(args.query, tags.project.tag);
|
|
370
|
-
if (!result.success) {
|
|
371
|
-
return JSON.stringify({
|
|
372
|
-
success: false,
|
|
373
|
-
error: result.error || "Failed to search memories",
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
return formatSearchResults(args.query, scope, result, args.limit);
|
|
377
|
-
}
|
|
378
|
-
const [userResult, projectResult] = await Promise.all([
|
|
379
|
-
memoryClient.searchMemories(args.query, tags.user.tag),
|
|
380
|
-
memoryClient.searchMemories(args.query, tags.project.tag),
|
|
381
|
-
]);
|
|
382
|
-
if (!userResult.success || !projectResult.success) {
|
|
347
|
+
const result = await memoryClient.searchMemories(args.query, tags.project.tag);
|
|
348
|
+
if (!result.success) {
|
|
383
349
|
return JSON.stringify({
|
|
384
350
|
success: false,
|
|
385
|
-
error:
|
|
351
|
+
error: result.error || "Failed to search memories",
|
|
386
352
|
});
|
|
387
353
|
}
|
|
388
|
-
|
|
389
|
-
...(userResult.results || []).map((r) => ({
|
|
390
|
-
...r,
|
|
391
|
-
scope: "user",
|
|
392
|
-
})),
|
|
393
|
-
...(projectResult.results || []).map((r) => ({
|
|
394
|
-
...r,
|
|
395
|
-
scope: "project",
|
|
396
|
-
})),
|
|
397
|
-
].sort((a, b) => b.similarity - a.similarity);
|
|
398
|
-
return JSON.stringify({
|
|
399
|
-
success: true,
|
|
400
|
-
query: args.query,
|
|
401
|
-
count: combined.length,
|
|
402
|
-
results: combined.slice(0, args.limit || 10).map((r) => ({
|
|
403
|
-
id: r.id,
|
|
404
|
-
content: r.memory || r.chunk,
|
|
405
|
-
similarity: Math.round(r.similarity * 100),
|
|
406
|
-
scope: r.scope,
|
|
407
|
-
})),
|
|
408
|
-
});
|
|
354
|
+
return formatSearchResults(args.query, result, args.limit);
|
|
409
355
|
}
|
|
410
356
|
case "profile": {
|
|
411
357
|
const { userProfileManager } = await import("./services/user-profile/user-profile-manager.js");
|
|
@@ -433,10 +379,8 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
433
379
|
});
|
|
434
380
|
}
|
|
435
381
|
case "list": {
|
|
436
|
-
const scope = args.scope || "project";
|
|
437
382
|
const limit = args.limit || 20;
|
|
438
|
-
const
|
|
439
|
-
const result = await memoryClient.listMemories(tagInfo.tag, limit);
|
|
383
|
+
const result = await memoryClient.listMemories(tags.project.tag, limit);
|
|
440
384
|
if (!result.success) {
|
|
441
385
|
return JSON.stringify({
|
|
442
386
|
success: false,
|
|
@@ -446,7 +390,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
446
390
|
const memories = result.memories || [];
|
|
447
391
|
return JSON.stringify({
|
|
448
392
|
success: true,
|
|
449
|
-
scope,
|
|
450
393
|
count: memories.length,
|
|
451
394
|
memories: memories.map((m) => ({
|
|
452
395
|
id: m.id,
|
|
@@ -463,7 +406,6 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
463
406
|
error: "memoryId parameter is required for forget mode",
|
|
464
407
|
});
|
|
465
408
|
}
|
|
466
|
-
const scope = args.scope || "project";
|
|
467
409
|
const result = await memoryClient.deleteMemory(args.memoryId);
|
|
468
410
|
if (!result.success) {
|
|
469
411
|
return JSON.stringify({
|
|
@@ -473,7 +415,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
473
415
|
}
|
|
474
416
|
return JSON.stringify({
|
|
475
417
|
success: true,
|
|
476
|
-
message: `Memory ${args.memoryId} removed
|
|
418
|
+
message: `Memory ${args.memoryId} removed`,
|
|
477
419
|
});
|
|
478
420
|
}
|
|
479
421
|
case "capture-now": {
|
|
@@ -510,7 +452,7 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
510
452
|
if (sessionID) {
|
|
511
453
|
await performAutoCapture(ctx, sessionID, directory);
|
|
512
454
|
}
|
|
513
|
-
await
|
|
455
|
+
await performUserProfileLearning(ctx, directory);
|
|
514
456
|
const { cleanupService } = await import("./services/cleanup-service.js");
|
|
515
457
|
const shouldRun = await cleanupService.shouldRunCleanup();
|
|
516
458
|
if (!shouldRun)
|
|
@@ -550,12 +492,11 @@ export const OpenCodeMemPlugin = async (ctx) => {
|
|
|
550
492
|
},
|
|
551
493
|
};
|
|
552
494
|
};
|
|
553
|
-
function formatSearchResults(query,
|
|
495
|
+
function formatSearchResults(query, results, limit) {
|
|
554
496
|
const memoryResults = results.results || [];
|
|
555
497
|
return JSON.stringify({
|
|
556
498
|
success: true,
|
|
557
499
|
query,
|
|
558
|
-
scope,
|
|
559
500
|
count: memoryResults.length,
|
|
560
501
|
results: memoryResults.slice(0, limit || 10).map((r) => ({
|
|
561
502
|
id: r.id,
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";AACA,QAAA,MAAQ,iBAAiB,sCAA+B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,eAAe,iBAAiB,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
-
const __dirname = dirname(__filename);
|
|
6
2
|
const { OpenCodeMemPlugin } = await import("./index.js");
|
|
7
3
|
export { OpenCodeMemPlugin };
|
|
8
4
|
export default OpenCodeMemPlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA2BvF,qBAAa,yBAA0B,SAAQ,cAAc;IAC3D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAmJ1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,gBAAgB;
|
|
1
|
+
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA2BvF,qBAAa,yBAA0B,SAAQ,cAAc;IAC3D,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAmJ1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,gBAAgB;CAsBzB"}
|
|
@@ -153,24 +153,18 @@ export class AnthropicMessagesProvider extends BaseAIProvider {
|
|
|
153
153
|
if (!data || typeof data !== "object") {
|
|
154
154
|
throw new Error("Response is not an object");
|
|
155
155
|
}
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
return (m &&
|
|
159
|
-
typeof m === "object" &&
|
|
160
|
-
typeof m.summary === "string" &&
|
|
161
|
-
m.summary.trim().length > 0 &&
|
|
162
|
-
(m.scope === "user" || m.scope === "project") &&
|
|
163
|
-
typeof m.type === "string" &&
|
|
164
|
-
m.type.trim().length > 0);
|
|
165
|
-
});
|
|
166
|
-
if (validMemories.length === 0) {
|
|
167
|
-
throw new Error("No valid memories in response");
|
|
168
|
-
}
|
|
169
|
-
return { memories: validMemories };
|
|
156
|
+
if (Array.isArray(data)) {
|
|
157
|
+
throw new Error("Response cannot be an array");
|
|
170
158
|
}
|
|
171
|
-
|
|
172
|
-
|
|
159
|
+
const keys = Object.keys(data);
|
|
160
|
+
if (keys.length === 0) {
|
|
161
|
+
throw new Error("Response object is empty");
|
|
162
|
+
}
|
|
163
|
+
for (const key of keys) {
|
|
164
|
+
if (data[key] === undefined || data[key] === null) {
|
|
165
|
+
throw new Error(`Response field '${key}' is null or undefined`);
|
|
166
|
+
}
|
|
173
167
|
}
|
|
174
|
-
|
|
168
|
+
return data;
|
|
175
169
|
}
|
|
176
170
|
}
|
|
@@ -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;AAkBlE,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;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IA2K1B,OAAO,CAAC,gBAAgB;
|
|
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;AAkBlE,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;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IA2K1B,OAAO,CAAC,gBAAgB;CAsBzB"}
|
|
@@ -158,24 +158,18 @@ export class OpenAIChatCompletionProvider extends BaseAIProvider {
|
|
|
158
158
|
if (!data || typeof data !== "object") {
|
|
159
159
|
throw new Error("Response is not an object");
|
|
160
160
|
}
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
return (m &&
|
|
164
|
-
typeof m === "object" &&
|
|
165
|
-
typeof m.summary === "string" &&
|
|
166
|
-
m.summary.trim().length > 0 &&
|
|
167
|
-
(m.scope === "user" || m.scope === "project") &&
|
|
168
|
-
typeof m.type === "string" &&
|
|
169
|
-
m.type.trim().length > 0);
|
|
170
|
-
});
|
|
171
|
-
if (validMemories.length === 0) {
|
|
172
|
-
throw new Error("No valid memories in response");
|
|
173
|
-
}
|
|
174
|
-
return { memories: validMemories };
|
|
161
|
+
if (Array.isArray(data)) {
|
|
162
|
+
throw new Error("Response cannot be an array");
|
|
175
163
|
}
|
|
176
|
-
|
|
177
|
-
|
|
164
|
+
const keys = Object.keys(data);
|
|
165
|
+
if (keys.length === 0) {
|
|
166
|
+
throw new Error("Response object is empty");
|
|
167
|
+
}
|
|
168
|
+
for (const key of keys) {
|
|
169
|
+
if (data[key] === undefined || data[key] === null) {
|
|
170
|
+
throw new Error(`Response field '${key}' is null or undefined`);
|
|
171
|
+
}
|
|
178
172
|
}
|
|
179
|
-
|
|
173
|
+
return data;
|
|
180
174
|
}
|
|
181
175
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAuH1B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;
|
|
1
|
+
{"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../../../src/services/ai/providers/openai-responses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAsBvF,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,MAAM,EAAE,GAAG,EAAE,gBAAgB,EAAE,gBAAgB;IAK3D,eAAe,IAAI,MAAM;IAIzB,eAAe,IAAI,OAAO;IAIpB,eAAe,CACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAuH1B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;CAsBzB"}
|