@zilliz/memsearch-opencode 0.2.1 → 0.3.1
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 +19 -5
- package/index.ts +25 -8
- package/package.json +1 -1
- package/scripts/capture-daemon.py +352 -144
- package/scripts/opencode_turns.py +449 -0
- package/scripts/parse-transcript.py +61 -148
- package/skills/memory-recall/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -62,6 +62,7 @@ OpenCode Session
|
|
|
62
62
|
├── chat.message hook ──→ Detect turn completion
|
|
63
63
|
│ │
|
|
64
64
|
│ ├── Extract last turn from SQLite
|
|
65
|
+
│ ├── Persist turn metadata to .memsearch/opencode-turns.db
|
|
65
66
|
│ ├── Summarize via LLM (third-person notes)
|
|
66
67
|
│ └── Append to .memsearch/memory/YYYY-MM-DD.md
|
|
67
68
|
│ │
|
|
@@ -106,7 +107,11 @@ We discussed the authentication flow before, what was the approach?
|
|
|
106
107
|
|------|-------------|
|
|
107
108
|
| `memory_search` | Semantic search over past memories. Returns ranked chunks. |
|
|
108
109
|
| `memory_get` | Expand a chunk hash to see the full markdown section. |
|
|
109
|
-
| `memory_transcript` | Read original conversation from OpenCode SQLite DB. |
|
|
110
|
+
| `memory_transcript` | Read original conversation from OpenCode SQLite DB, optionally centered on a turn cursor. |
|
|
111
|
+
|
|
112
|
+
`<project>/.memsearch/opencode-turns.db` stores derived capture checkpoints and
|
|
113
|
+
turn ordering only. It is rebuildable state, not the source of truth for
|
|
114
|
+
transcript recall.
|
|
110
115
|
|
|
111
116
|
## Memory Files
|
|
112
117
|
|
|
@@ -127,7 +132,7 @@ Each file contains timestamped entries with bullet-point summaries:
|
|
|
127
132
|
## Session 14:30
|
|
128
133
|
|
|
129
134
|
### 14:30
|
|
130
|
-
<!-- session:ses_abc123 db:~/.local/share/opencode/opencode.db -->
|
|
135
|
+
<!-- session:ses_abc123 turn:msg_123abc db:~/.local/share/opencode/opencode.db -->
|
|
131
136
|
- User asked about the authentication flow.
|
|
132
137
|
- Assistant explained the OAuth2 implementation in auth.ts.
|
|
133
138
|
- Assistant modified the token refresh logic in refresh.ts.
|
|
@@ -143,13 +148,22 @@ memsearch config set embedding.provider openai
|
|
|
143
148
|
export OPENAI_API_KEY=sk-...
|
|
144
149
|
```
|
|
145
150
|
|
|
146
|
-
To override only the OpenCode capture summarization model:
|
|
151
|
+
To override only the OpenCode native capture summarization model:
|
|
147
152
|
|
|
148
153
|
```bash
|
|
149
154
|
memsearch config set plugins.opencode.summarize.model anthropic/claude-haiku
|
|
150
155
|
```
|
|
151
156
|
|
|
152
|
-
|
|
157
|
+
To use a memsearch-managed API provider instead:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
memsearch config set llm.providers.openai.type openai
|
|
161
|
+
memsearch config set llm.providers.openai.model gpt-4o-mini
|
|
162
|
+
memsearch config set llm.providers.openai.api_key env:OPENAI_API_KEY
|
|
163
|
+
memsearch config set plugins.opencode.summarize.provider openai
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Leave `plugins.opencode.summarize.provider` empty or set it to `native` to keep the current `small_model` / plugin default behavior. This setting does not fall back to `llm.model`.
|
|
153
167
|
|
|
154
168
|
## How It Works
|
|
155
169
|
|
|
@@ -157,7 +171,7 @@ Leave it empty or unset to keep the current `small_model` / plugin default behav
|
|
|
157
171
|
|
|
158
172
|
2. **Index**: The markdown files are indexed by memsearch into a Milvus collection (Milvus Lite by default, runs in-process).
|
|
159
173
|
|
|
160
|
-
3. **Recall**: When the assistant needs historical context, it calls `memory_search` to find relevant chunks. Results can be expanded with `memory_get` or drilled into with `memory_transcript
|
|
174
|
+
3. **Recall**: When the assistant needs historical context, it calls `memory_search` to find relevant chunks. Results can be expanded with `memory_get` or drilled into with `memory_transcript`, which reads the original transcript from OpenCode SQLite.
|
|
161
175
|
|
|
162
176
|
4. **Cold-start**: At session start, recent memory bullets are injected into the system prompt so the assistant has immediate context.
|
|
163
177
|
|
package/index.ts
CHANGED
|
@@ -285,11 +285,14 @@ const MemsearchPlugin: Plugin = async ({ project, directory, worktree }) => {
|
|
|
285
285
|
description:
|
|
286
286
|
"Retrieve the original conversation from a past OpenCode session. " +
|
|
287
287
|
"Use after memory_get when the expanded result contains a session anchor " +
|
|
288
|
-
"(<!-- session:ID db:PATH -->). Returns the formatted " +
|
|
289
|
-
"dialogue with [Human] and [Assistant] labels."
|
|
288
|
+
"(<!-- session:ID turn:ID db:PATH -->). Returns the formatted " +
|
|
289
|
+
"dialogue with [Human] and [Assistant] labels. When turn_id is present, " +
|
|
290
|
+
"the tool returns the target turn plus surrounding context.",
|
|
290
291
|
args: {
|
|
291
292
|
session_id: tool.schema.string().describe("The session ID from the anchor comment"),
|
|
292
|
-
|
|
293
|
+
turn_id: tool.schema.string().optional().describe("Optional turn ID from the anchor comment"),
|
|
294
|
+
context: tool.schema.number().optional().describe("Turns before/after the target turn (default: 3)"),
|
|
295
|
+
limit: tool.schema.number().optional().describe("Max number of turns to return when no turn_id is provided (default: 20)"),
|
|
293
296
|
},
|
|
294
297
|
async execute(args, context) {
|
|
295
298
|
const dir = context?.directory || projectDir;
|
|
@@ -297,11 +300,25 @@ const MemsearchPlugin: Plugin = async ({ project, directory, worktree }) => {
|
|
|
297
300
|
if (autoCapture) startCaptureDaemon(dir, col, memsearchCmd);
|
|
298
301
|
try {
|
|
299
302
|
const scriptPath = join(PLUGIN_DIR, "scripts", "parse-transcript.py");
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
303
|
+
const scriptArgs = [
|
|
304
|
+
scriptPath,
|
|
305
|
+
args.session_id,
|
|
306
|
+
"--project-dir",
|
|
307
|
+
dir,
|
|
308
|
+
];
|
|
309
|
+
if (args.turn_id) {
|
|
310
|
+
scriptArgs.push("--turn", args.turn_id);
|
|
311
|
+
}
|
|
312
|
+
if (typeof args.context === "number") {
|
|
313
|
+
scriptArgs.push("--context", String(args.context));
|
|
314
|
+
}
|
|
315
|
+
if (typeof args.limit === "number") {
|
|
316
|
+
scriptArgs.push("--limit", String(args.limit));
|
|
317
|
+
}
|
|
318
|
+
const result = spawnSync("python3", scriptArgs, {
|
|
319
|
+
encoding: "utf-8",
|
|
320
|
+
timeout: 15000,
|
|
321
|
+
});
|
|
305
322
|
return result.stdout?.trim() || result.stderr || "No transcript content found.";
|
|
306
323
|
} catch (e: any) {
|
|
307
324
|
return `Transcript parse failed: ${e.message}`;
|