@batonfx/memory 0.3.4 → 0.3.5

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.
@@ -1,5 +1,5 @@
1
1
  $ bun build ./src/index.ts --outdir dist --target bun --format esm
2
- Bundled 176 modules in 523ms
2
+ Bundled 176 modules in 390ms
3
3
 
4
4
  index.js 1.1 MB (entry point)
5
5
 
package/dist/index.js CHANGED
@@ -32865,7 +32865,11 @@ var make37 = exports_Ref.make(exports_HashMap.empty()).pipe(exports_Effect.map((
32865
32865
  }
32866
32866
  return matches.toSorted((left, right) => right.score - left.score).slice(0, input.limit);
32867
32867
  }),
32868
- delete: (input) => exports_Ref.update(documents, (current) => exports_HashMap.filter(current, (document) => !sameKey(document.key, input.key)))
32868
+ delete: (input) => exports_Ref.update(documents, (current) => exports_HashMap.filter(current, (document) => {
32869
+ if (!sameKey(document.key, input.key))
32870
+ return true;
32871
+ return input.id === undefined ? false : document.id !== input.id;
32872
+ }))
32869
32873
  })));
32870
32874
  var memoryLayer2 = exports_Layer.effect(VectorStore, make37.pipe(exports_Effect.map(VectorStore.of)));
32871
32875
  var testLayer2 = (implementation) => exports_Layer.succeed(VectorStore, VectorStore.of(implementation));
@@ -32943,7 +32947,7 @@ var make38 = (options = {}) => exports_Effect.gen(function* () {
32943
32947
  }
32944
32948
  ])))), exports_Effect.mapError(memoryError));
32945
32949
  },
32946
- forget: (input) => store.delete({ key: input.key }).pipe(exports_Effect.mapError(memoryError))
32950
+ forget: (input) => store.delete(input).pipe(exports_Effect.mapError(memoryError))
32947
32951
  };
32948
32952
  });
32949
32953
  var makeSemanticRecall = make38;
@@ -33069,7 +33073,24 @@ var make39 = (options = {}) => exports_Ref.make(exports_HashMap.empty()).pipe(ex
33069
33073
  yield* exports_Ref.update(states, exports_HashMap.set(id2, nextState));
33070
33074
  });
33071
33075
  },
33072
- forget: (input) => exports_Ref.update(states, exports_HashMap.remove(keyId(input.key)))
33076
+ forget: (input) => exports_Ref.update(states, (current) => {
33077
+ const id2 = keyId(input.key);
33078
+ if (input.id === undefined)
33079
+ return exports_HashMap.remove(current, id2);
33080
+ const existing = exports_HashMap.get(current, id2);
33081
+ if (existing._tag === "None")
33082
+ return current;
33083
+ const summary = input.id === "working-summary" ? undefined : existing.value.summary;
33084
+ const recent = existing.value.recent.filter((item) => item.id !== input.id);
33085
+ if (summary === undefined && recent.length === 0)
33086
+ return exports_HashMap.remove(current, id2);
33087
+ const nextState = {
33088
+ recent,
33089
+ counter: existing.value.counter,
33090
+ ...summary === undefined ? {} : { summary }
33091
+ };
33092
+ return exports_HashMap.set(current, id2, nextState);
33093
+ })
33073
33094
  };
33074
33095
  }));
33075
33096
  var makeWorkingMemory = make39;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@batonfx/memory",
4
- "version": "0.3.4",
4
+ "version": "0.3.5",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "exports": {
@@ -14,7 +14,7 @@
14
14
  "typecheck": "bun tsc --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "@batonfx/core": "0.3.4",
17
+ "@batonfx/core": "0.3.5",
18
18
  "effect": "4.0.0-beta.93"
19
19
  },
20
20
  "devDependencies": {
@@ -109,7 +109,7 @@ export const make = (
109
109
  Effect.mapError(memoryError),
110
110
  )
111
111
  },
112
- forget: (input) => store.delete({ key: input.key }).pipe(Effect.mapError(memoryError)),
112
+ forget: (input) => store.delete(input).pipe(Effect.mapError(memoryError)),
113
113
  }
114
114
  })
115
115
 
@@ -31,6 +31,7 @@ export interface Query {
31
31
  /** @experimental */
32
32
  export interface DeleteInput {
33
33
  readonly key: Memory.Key
34
+ readonly id?: string | undefined
34
35
  }
35
36
 
36
37
  /** @experimental */
@@ -113,7 +114,12 @@ const make = Ref.make(HashMap.empty<string, Embedded>()).pipe(
113
114
  return matches.toSorted((left, right) => right.score - left.score).slice(0, input.limit)
114
115
  }),
115
116
  delete: (input) =>
116
- Ref.update(documents, (current) => HashMap.filter(current, (document) => !sameKey(document.key, input.key))),
117
+ Ref.update(documents, (current) =>
118
+ HashMap.filter(current, (document) => {
119
+ if (!sameKey(document.key, input.key)) return true
120
+ return input.id === undefined ? false : document.id !== input.id
121
+ }),
122
+ ),
117
123
  }),
118
124
  ),
119
125
  )
@@ -180,7 +180,22 @@ export const make = (options: Options = {}): Effect.Effect<Memory.Interface> =>
180
180
  yield* Ref.update(states, HashMap.set(id, nextState))
181
181
  })
182
182
  },
183
- forget: (input) => Ref.update(states, HashMap.remove(keyId(input.key))),
183
+ forget: (input) =>
184
+ Ref.update(states, (current) => {
185
+ const id = keyId(input.key)
186
+ if (input.id === undefined) return HashMap.remove(current, id)
187
+ const existing = HashMap.get(current, id)
188
+ if (existing._tag === "None") return current
189
+ const summary = input.id === "working-summary" ? undefined : existing.value.summary
190
+ const recent = existing.value.recent.filter((item) => item.id !== input.id)
191
+ if (summary === undefined && recent.length === 0) return HashMap.remove(current, id)
192
+ const nextState: KeyState = {
193
+ recent,
194
+ counter: existing.value.counter,
195
+ ...(summary === undefined ? {} : { summary }),
196
+ }
197
+ return HashMap.set(current, id, nextState)
198
+ }),
184
199
  }
185
200
  }),
186
201
  )
@@ -91,6 +91,39 @@ describe("SemanticRecall", () => {
91
91
  }).pipe(Effect.provide(memoryLayer)),
92
92
  )
93
93
 
94
+ it.effect("forgets one semantic memory id within the exact memory key", () =>
95
+ Effect.gen(function* () {
96
+ const memory = yield* Memory.Memory
97
+
98
+ yield* memory.remember({
99
+ key,
100
+ turn: 0,
101
+ terminal: true,
102
+ transcript: prompt(user("What color is the sky?"), assistant("blue")),
103
+ })
104
+ yield* memory.remember({
105
+ key,
106
+ turn: 1,
107
+ terminal: true,
108
+ transcript: prompt(user("What color is the ocean?"), assistant("blue")),
109
+ })
110
+ yield* memory.remember({
111
+ key: otherKey,
112
+ turn: 0,
113
+ terminal: true,
114
+ transcript: prompt(user("What color is the door?"), assistant("blue")),
115
+ })
116
+
117
+ yield* memory.forget({ key, id: "semantic-1" })
118
+
119
+ const retained = yield* memory.recall({ key, turn: 0, prompt: prompt(user("color")) })
120
+ const otherRetained = yield* memory.recall({ key: otherKey, turn: 0, prompt: prompt(user("color")) })
121
+
122
+ expect(retained.map(itemText)).toEqual(["User: What color is the ocean?\nAssistant: blue"])
123
+ expect(otherRetained.map(itemText)).toEqual(["User: What color is the door?\nAssistant: blue"])
124
+ }).pipe(Effect.provide(memoryLayer)),
125
+ )
126
+
94
127
  it.effect("maps embedding failures to MemoryError", () => {
95
128
  const embeddingError = AiError.make({
96
129
  module: "SemanticRecallTest",
@@ -98,4 +98,24 @@ describe("VectorStore", () => {
98
98
  expect(remainingMatches.map((match) => match.document.text)).toEqual(["other subject"])
99
99
  }).pipe(Effect.provide(VectorStore.memoryLayer)),
100
100
  )
101
+
102
+ it.effect("deletes one document id within the exact memory key", () =>
103
+ Effect.gen(function* () {
104
+ const store = yield* VectorStore.VectorStore
105
+
106
+ yield* store.upsert([
107
+ document("first", key, "first", [1, 0]),
108
+ document("second", key, "second", [0, 1]),
109
+ document("first", otherSubject, "other subject", [1, 0]),
110
+ ])
111
+
112
+ yield* store.delete({ key, id: "first" })
113
+
114
+ const deletedKeyMatches = yield* store.query({ key, embedding: [1, 0], limit: 10 })
115
+ const otherSubjectMatches = yield* store.query({ key: otherSubject, embedding: [1, 0], limit: 10 })
116
+
117
+ expect(deletedKeyMatches.map((match) => match.document.text)).toEqual(["second"])
118
+ expect(otherSubjectMatches.map((match) => match.document.text)).toEqual(["other subject"])
119
+ }).pipe(Effect.provide(VectorStore.memoryLayer)),
120
+ )
101
121
  })
@@ -125,4 +125,31 @@ describe("WorkingMemory", () => {
125
125
  expect(retained.map(itemText)).toEqual(["User: three", "Assistant: four"])
126
126
  }).pipe(Effect.provide(WorkingMemory.layer({ maxMessages: 2 }))),
127
127
  )
128
+
129
+ it.effect("forgets one recalled item id within the exact memory key", () =>
130
+ Effect.gen(function* () {
131
+ const memory = yield* Memory.Memory
132
+
133
+ yield* memory.remember({
134
+ key,
135
+ turn: 0,
136
+ terminal: true,
137
+ transcript: prompt(user("one"), assistant("two")),
138
+ })
139
+ yield* memory.remember({
140
+ key: otherKey,
141
+ turn: 0,
142
+ terminal: true,
143
+ transcript: prompt(user("three"), assistant("four")),
144
+ })
145
+
146
+ yield* memory.forget({ key, id: "working-1" })
147
+
148
+ const retained = yield* memory.recall({ key, turn: 0, prompt: prompt(user("current")) })
149
+ const otherRetained = yield* memory.recall({ key: otherKey, turn: 0, prompt: prompt(user("current")) })
150
+
151
+ expect(retained.map(itemText)).toEqual(["Assistant: two"])
152
+ expect(otherRetained.map(itemText)).toEqual(["User: three", "Assistant: four"])
153
+ }).pipe(Effect.provide(WorkingMemory.layer({ maxMessages: 2 }))),
154
+ )
128
155
  })