Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). Versions follow

---

## [0.2.2] - 2026-03-21

### Fixed

- `memory_scope_promote`, `memory_delete`, `memory_feedback_wrong`, `memory_feedback_useful` now accept 8-character short IDs (prefix of UUID) in addition to full 36-character UUIDs. Previously, passing a short ID always returned "not found" even though `memory_search` could find the same memory.
- `id` parameter minimum length raised from 6 to 8 characters on all memory tools.
- Fix: DELETE inside `updateMemoryScope` and `updateMemoryUsage` now uses resolved `match.id`, not the prefix argument.

---

## [0.2.1] - 2026-03-21

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lancedb-opencode-pro",
"version": "0.2.1",
"version": "0.2.2",
"description": "LanceDB-backed long-term memory provider for OpenCode",
"type": "module",
"main": "dist/index.js",
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ const plugin: Plugin = async (input) => {
memory_delete: tool({
description: "Delete one memory entry by id",
args: {
id: tool.schema.string().min(6),
id: tool.schema.string().min(8),
scope: tool.schema.string().optional(),
confirm: tool.schema.boolean().default(false),
},
Expand Down Expand Up @@ -254,7 +254,7 @@ const plugin: Plugin = async (input) => {
memory_feedback_wrong: tool({
description: "Record feedback for memory that should not be stored",
args: {
id: tool.schema.string().min(6),
id: tool.schema.string().min(8),
reason: tool.schema.string().optional(),
scope: tool.schema.string().optional(),
},
Expand Down Expand Up @@ -284,7 +284,7 @@ const plugin: Plugin = async (input) => {
memory_feedback_useful: tool({
description: "Record whether a recalled memory was helpful",
args: {
id: tool.schema.string().min(6),
id: tool.schema.string().min(8),
helpful: tool.schema.boolean(),
scope: tool.schema.string().optional(),
},
Expand Down Expand Up @@ -327,7 +327,7 @@ const plugin: Plugin = async (input) => {
memory_scope_promote: tool({
description: "Promote a memory from project scope to global scope for cross-project sharing",
args: {
id: tool.schema.string().min(6),
id: tool.schema.string().min(8),
confirm: tool.schema.boolean().default(false),
},
execute: async (args, context) => {
Expand All @@ -352,7 +352,7 @@ const plugin: Plugin = async (input) => {
memory_scope_demote: tool({
description: "Demote a memory from global scope to project scope",
args: {
id: tool.schema.string().min(6),
id: tool.schema.string().min(8),
confirm: tool.schema.boolean().default(false),
scope: tool.schema.string().optional(),
},
Expand Down
17 changes: 11 additions & 6 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export class MemoryStore {

async deleteById(id: string, scopes: string[]): Promise<boolean> {
const rows = await this.readByScopes(scopes);
const match = rows.find((row) => row.id === id);
const match = rows.find((row) => this.matchesId(row.id, id));
if (!match) return false;
await this.requireTable().delete(`id = '${escapeSql(match.id)}'`);
this.invalidateScope(match.scope);
Expand All @@ -231,10 +231,10 @@ export class MemoryStore {

async updateMemoryScope(id: string, newScope: string, scopes: string[]): Promise<boolean> {
const rows = await this.readByScopes(scopes);
const match = rows.find((row) => row.id === id);
const match = rows.find((row) => this.matchesId(row.id, id));
if (!match) return false;

await this.requireTable().delete(`id = '${escapeSql(id)}'`);
await this.requireTable().delete(`id = '${escapeSql(match.id)}'`);
this.invalidateScope(match.scope);

await this.requireTable().add([{ ...match, scope: newScope }]);
Expand Down Expand Up @@ -282,10 +282,15 @@ export class MemoryStore {
return rows.filter((row) => row.vectorDim !== expectedDim).length;
}

private matchesId(candidateId: string, query: string): boolean {
if (query.length >= 36) return candidateId === query;
return candidateId.startsWith(query);
}

async hasMemory(id: string, scopes: string[]): Promise<boolean> {
for (let attempt = 0; attempt < 3; attempt++) {
const rows = await this.readByScopes(scopes);
if (rows.some((row) => row.id === id)) {
if (rows.some((row) => this.matchesId(row.id, id))) {
return true;
}
if (attempt < 2) {
Expand All @@ -297,7 +302,7 @@ export class MemoryStore {

async updateMemoryUsage(id: string, projectScope: string, scopes: string[]): Promise<void> {
const rows = await this.readByScopes(scopes);
const match = rows.find((row) => row.id === id);
const match = rows.find((row) => this.matchesId(row.id, id));
if (!match) return;

const now = Date.now();
Expand All @@ -321,7 +326,7 @@ export class MemoryStore {
}
}

await this.requireTable().delete(`id = '${escapeSql(id)}'`);
await this.requireTable().delete(`id = '${escapeSql(match.id)}'`);
this.invalidateScope(match.scope);

await this.requireTable().add([{
Expand Down
Loading