From f3b24cc0afed4a63fd26457fe24c195b39c5a247 Mon Sep 17 00:00:00 2001 From: Fallenhh Date: Fri, 18 Apr 2025 16:26:18 -0700 Subject: [PATCH 1/4] implementing long term memory with sqlite-vec --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 3 + configs/.gitignore | 2 +- configs/config.yaml-template | 3 +- package.json | 2 +- src/plugins/long-term-memory/init.ts | 199 ++++++++++++--------------- 6 files changed, 96 insertions(+), 113 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..11a89191fae6edd51927b2d58bb8e82b5dc204ac GIT binary patch literal 6148 zcmeHK!A=`75Pc3S1yWie^}=z_l?Z}sFI$?Zic~l>9{|Z_8_{ldtB^$MZGVRgH$I?W z*1j3L)ZW0gs)|RlpJUIPvEOFxH2`zAo}B;(0CrgflOC%_Ova^bS;zGV*=USw%yBa+ z>wH>ndB={ZKvdvgQ$XI`E^^eU@EP9wTTeM6qaRpKf2y&y<-Hj%tFo@<9N`{-1T#jt z!OHFe4^e(_%#YH;fH`w~MS-PeE>VOW^R~s2*urr;%_ROi|0c@zi=Lkr?&Q zzx9c=i)H~c!G=mz*n}BGqri{TdNwBSD{c3M#aKrLq5@HY2L)t*NLd6khmA$uI#}ry zfS9mbjcxg85KihabJ$qq2+de3(Nc}OVi-$jf9m`)hmA!`hjEt=<1!m}Lou42@l$n& z$t=b?Di9S271*&q59ItGK7IcWN%2=yAS&=*DPWSpcyPugxwCa^adOtCELSXI;@4PI k3M+RUYeSCWLl!lTrP3f~4jYT?p~VjYl_6G9fxoK2FK0vGHvj+t literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index c6bba59..366f89a 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# Database +long-term-memory.db \ No newline at end of file diff --git a/configs/.gitignore b/configs/.gitignore index ea27a25..5051c01 100644 --- a/configs/.gitignore +++ b/configs/.gitignore @@ -1,4 +1,4 @@ * !.gitignore !*example -!*template +!*template \ No newline at end of file diff --git a/configs/config.yaml-template b/configs/config.yaml-template index 1ac1c9d..f38eb40 100644 --- a/configs/config.yaml-template +++ b/configs/config.yaml-template @@ -56,8 +56,7 @@ plugins: vector_model: text-embedding-3-small dimensions: 100 max_query_results: 3 - persist_db: true - db_file: configs/long-term-memory.db + persist_db: false discord: bot_token: your-discord-bot-token allowed_channel_ids: diff --git a/package.json b/package.json index c55f169..1853ee7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "dev": "tsx watch --include ./src src/main.ts configs/config.yaml", "start": "npm run build && npm run fast-start", - "fast-start": "node dist/main.js configs/config.yaml", + "fast-start": "node --experimental-sqlite dist/main.js configs/config.yaml", "build": "npm run clean && npm run fast-build", "fast-build": "swc src -d dist --strip-leading-paths", "clean": "rm -rf dist", diff --git a/src/plugins/long-term-memory/init.ts b/src/plugins/long-term-memory/init.ts index 50b73af..93c9506 100644 --- a/src/plugins/long-term-memory/init.ts +++ b/src/plugins/long-term-memory/init.ts @@ -47,134 +47,115 @@ export default class LongTermMemory extends PluginBase { defaultHeaders: openaiDefaultHeaders, }); - athena.registerTool( - { - name: "ltm/store", - desc: "Store some data to your long-term memory.", - args: { - desc: { - type: "string", - desc: "A description of the data.", - required: true, - }, - data: { - type: "object", - desc: "The data to store.", - required: true, - }, + athena.registerTool({ + name: "ltm/store", + desc: "Store some data to your long-term memory.", + args: { + desc: { + type: "string", + desc: "A description of the data.", + required: true, }, - retvals: { - status: { - type: "string", - desc: "The status of the operation.", - required: true, - }, + data: { + type: "object", + desc: "The data to store.", + required: true, }, }, - { - fn: async (args: Dict) => { - const embedding = await this.openai.embeddings.create({ - model: this.config.vector_model, - dimensions: this.config.dimensions, - input: args.desc, - encoding_format: "float", - }); - insertStmt.run( - Float32Array.from(embedding.data[0].embedding), - args.desc, - JSON.stringify(args.data), - ); - return { status: "success" }; + retvals: { + status: { + type: "string", + desc: "The status of the operation.", + required: true, }, }, - ); - // TODO: Implement remove - athena.registerTool( - { - name: "ltm/list", - desc: "List your long-term memory.", - args: {}, - retvals: { - list: { - type: "array", - desc: "The list of metadata of the long-term memory.", - required: true, + fn: async (args: Dict) => { + const embedding = await this.openai.embeddings.create({ + model: this.config.vector_model, + dimensions: this.config.dimensions, + input: args.desc, + encoding_format: "float", + }); + insertStmt.run( + Float32Array.from(embedding.data[0].embedding), + args.desc, + JSON.stringify(args.data), + ); + return { status: "success" }; + }, + }); + athena.registerTool({ + name: "ltm/list", + desc: "List your long-term memory.", + args: {}, + retvals: { + list: { + type: "array", + desc: "The list of metadata of the long-term memory.", + required: true, + of: { + type: "object", + desc: "The metadata of the long-term memory.", + required: false, of: { - type: "object", - desc: "The metadata of the long-term memory.", - required: false, - of: { - desc: { - type: "string", - desc: "The description of the data.", - required: true, - }, + desc: { + type: "string", + desc: "The description of the data.", + required: true, }, }, }, }, }, - { - fn: async (args: Dict) => { - const list = this.db - .prepare("SELECT desc, data FROM vec_items") - .all(); - return { - list: list.map((item) => ({ - desc: String(item.desc), - data: JSON.parse(String(item.data)), - })), - }; - }, + fn: async (args: Dict) => { + const list = this.db.prepare("SELECT desc, data FROM vec_items").all(); + return { list: list }; }, - ); - athena.registerTool( - { - name: "ltm/retrieve", - desc: "Retrieve data from your long-term memory.", - args: { - query: { - type: "string", - desc: "The query to retrieve the data.", - required: true, - }, + }); + athena.registerTool({ + name: "ltm/retrieve", + desc: "Retrieve data from your long-term memory.", + args: { + query: { + type: "string", + desc: "The query to retrieve the data.", + required: true, }, - retvals: { - list: { - type: "array", - desc: "Query results list of metadata of the long-term memory.", - required: true, + }, + retvals: { + list: { + type: "array", + desc: "Query results list of metadata of the long-term memory.", + required: true, + of: { + type: "object", + desc: "The desc and data of the long-term memory.", + required: false, of: { - type: "object", - desc: "The desc and data of the long-term memory.", - required: false, - of: { - desc: { - type: "string", - desc: "The description of the data.", - required: true, - }, - data: { - type: "object", - desc: "The data.", - required: true, - }, + desc: { + type: "string", + desc: "The description of the data.", + required: true, + }, + data: { + type: "object", + desc: "The data.", + required: true, }, }, }, }, }, - { - fn: async (args) => { - const embedding = await this.openai.embeddings.create({ - model: this.config.vector_model, - dimensions: this.config.dimensions, - input: args.query, - encoding_format: "float", - }); - const results = this.db - .prepare( - `SELECT + fn: async (args: Dict) => { + const embedding = await this.openai.embeddings.create({ + model: this.config.vector_model, + dimensions: this.config.dimensions, + input: args.query, + encoding_format: "float", + }); + const results = this.db + .prepare( + `SELECT distance, desc, data From b0b1240e3609fe0f23c29f1b3058a2cd2ef6693b Mon Sep 17 00:00:00 2001 From: Fallenhh Date: Mon, 21 Apr 2025 13:56:50 -0700 Subject: [PATCH 2/4] # This is a combination of 2 commits. # This is the 1st commit message: support update ltm changing the embedding to be desc + data, support inverse search # The commit message #2 will be skipped: # linting --- src/plugins/long-term-memory/init.ts | 57 +++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/plugins/long-term-memory/init.ts b/src/plugins/long-term-memory/init.ts index 50b73af..4f734b9 100644 --- a/src/plugins/long-term-memory/init.ts +++ b/src/plugins/long-term-memory/init.ts @@ -76,7 +76,7 @@ export default class LongTermMemory extends PluginBase { const embedding = await this.openai.embeddings.create({ model: this.config.vector_model, dimensions: this.config.dimensions, - input: args.desc, + input: args.desc + JSON.stringify(args.new_data), encoding_format: "float", }); insertStmt.run( @@ -88,6 +88,60 @@ export default class LongTermMemory extends PluginBase { }, }, ); + + athena.registerTool( + { + name: "ltm/update", + desc: "Update existing data in your long-term memory.", + args: { + desc: { + type: "string", + desc: "The description of the data.", + required: true, + }, + new_data: { + type: "object", + desc: "The new data to update the existing data with.", + required: true, + }, + }, + retvals: { + status: { + type: "string", + desc: "The status of the operation.", + required: true, + }, + }, + }, + { + fn: async (args: Dict) => { + const existingItem = this.db + .prepare("SELECT * FROM vec_items WHERE desc = ?") + .get(args.desc); + if (!existingItem) { + throw new Error("Item not found"); + } + this.db + .prepare("DELETE FROM vec_items WHERE desc = ?") + .run(args.desc); + + const new_embedding = await this.openai.embeddings.create({ + model: this.config.vector_model, + dimensions: this.config.dimensions, + input: args.desc + JSON.stringify(args.new_data), + encoding_format: "float", + }); + + insertStmt.run( + Float32Array.from(new_embedding.data[0].embedding), + args.desc, + JSON.stringify(args.new_data), + ); + return { status: "success" }; + }, + }, + ); + // TODO: Implement remove athena.registerTool( { @@ -205,6 +259,7 @@ export default class LongTermMemory extends PluginBase { async unload(athena: Athena) { athena.deregisterTool("ltm/store"); + athena.deregisterTool("ltm/update"); athena.deregisterTool("ltm/list"); athena.deregisterTool("ltm/retrieve"); } From dfc7b5073b8eb5a1cb105fb5fa5008a1777aa2b5 Mon Sep 17 00:00:00 2001 From: Fallenhh Date: Mon, 21 Apr 2025 14:24:30 -0700 Subject: [PATCH 3/4] merge --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 3 +++ configs/.gitignore | 2 +- configs/config.yaml-template | 3 +-- package.json | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..11a89191fae6edd51927b2d58bb8e82b5dc204ac GIT binary patch literal 6148 zcmeHK!A=`75Pc3S1yWie^}=z_l?Z}sFI$?Zic~l>9{|Z_8_{ldtB^$MZGVRgH$I?W z*1j3L)ZW0gs)|RlpJUIPvEOFxH2`zAo}B;(0CrgflOC%_Ova^bS;zGV*=USw%yBa+ z>wH>ndB={ZKvdvgQ$XI`E^^eU@EP9wTTeM6qaRpKf2y&y<-Hj%tFo@<9N`{-1T#jt z!OHFe4^e(_%#YH;fH`w~MS-PeE>VOW^R~s2*urr;%_ROi|0c@zi=Lkr?&Q zzx9c=i)H~c!G=mz*n}BGqri{TdNwBSD{c3M#aKrLq5@HY2L)t*NLd6khmA$uI#}ry zfS9mbjcxg85KihabJ$qq2+de3(Nc}OVi-$jf9m`)hmA!`hjEt=<1!m}Lou42@l$n& z$t=b?Di9S271*&q59ItGK7IcWN%2=yAS&=*DPWSpcyPugxwCa^adOtCELSXI;@4PI k3M+RUYeSCWLl!lTrP3f~4jYT?p~VjYl_6G9fxoK2FK0vGHvj+t literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index c6bba59..366f89a 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# Database +long-term-memory.db \ No newline at end of file diff --git a/configs/.gitignore b/configs/.gitignore index ea27a25..5051c01 100644 --- a/configs/.gitignore +++ b/configs/.gitignore @@ -1,4 +1,4 @@ * !.gitignore !*example -!*template +!*template \ No newline at end of file diff --git a/configs/config.yaml-template b/configs/config.yaml-template index 1ac1c9d..f38eb40 100644 --- a/configs/config.yaml-template +++ b/configs/config.yaml-template @@ -56,8 +56,7 @@ plugins: vector_model: text-embedding-3-small dimensions: 100 max_query_results: 3 - persist_db: true - db_file: configs/long-term-memory.db + persist_db: false discord: bot_token: your-discord-bot-token allowed_channel_ids: diff --git a/package.json b/package.json index c55f169..1853ee7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "dev": "tsx watch --include ./src src/main.ts configs/config.yaml", "start": "npm run build && npm run fast-start", - "fast-start": "node dist/main.js configs/config.yaml", + "fast-start": "node --experimental-sqlite dist/main.js configs/config.yaml", "build": "npm run clean && npm run fast-build", "fast-build": "swc src -d dist --strip-leading-paths", "clean": "rm -rf dist", From 6466ecf771cf4218e286dc8bc3c65e227126a2c1 Mon Sep 17 00:00:00 2001 From: Fallenhh Date: Mon, 21 Apr 2025 14:25:15 -0700 Subject: [PATCH 4/4] support update ltm changing the embedding to be desc + data, support inverse search --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 11a89191fae6edd51927b2d58bb8e82b5dc204ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!A=`75Pc3S1yWie^}=z_l?Z}sFI$?Zic~l>9{|Z_8_{ldtB^$MZGVRgH$I?W z*1j3L)ZW0gs)|RlpJUIPvEOFxH2`zAo}B;(0CrgflOC%_Ova^bS;zGV*=USw%yBa+ z>wH>ndB={ZKvdvgQ$XI`E^^eU@EP9wTTeM6qaRpKf2y&y<-Hj%tFo@<9N`{-1T#jt z!OHFe4^e(_%#YH;fH`w~MS-PeE>VOW^R~s2*urr;%_ROi|0c@zi=Lkr?&Q zzx9c=i)H~c!G=mz*n}BGqri{TdNwBSD{c3M#aKrLq5@HY2L)t*NLd6khmA$uI#}ry zfS9mbjcxg85KihabJ$qq2+de3(Nc}OVi-$jf9m`)hmA!`hjEt=<1!m}Lou42@l$n& z$t=b?Di9S271*&q59ItGK7IcWN%2=yAS&=*DPWSpcyPugxwCa^adOtCELSXI;@4PI k3M+RUYeSCWLl!lTrP3f~4jYT?p~VjYl_6G9fxoK2FK0vGHvj+t