Skip to content

Commit 1b34bd9

Browse files
committed
fix(memory): tokenize query and events alike in InMemoryMemoryService
Matches adk-python: both sides are split with a Unicode-aware \w+, so a query word followed by punctuation, a word with accented letters and a number now match. Before, the query was split on whitespace only and events kept only ASCII letters.
1 parent 4092a1f commit 1b34bd9

2 files changed

Lines changed: 52 additions & 10 deletions

File tree

‎core/src/main/java/com/google/adk/memory/InMemoryMemoryService.java‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@
4444
*/
4545
public final class InMemoryMemoryService implements BaseMemoryService {
4646

47-
// Pattern to extract words, matching the Python version.
48-
private static final Pattern WORD_PATTERN = Pattern.compile("[A-Za-z]+");
47+
// Pattern to extract words, matching Python's Unicode-aware \w+.
48+
private static final Pattern WORD_PATTERN =
49+
Pattern.compile("\\w+", Pattern.UNICODE_CHARACTER_CLASS);
4950

5051
/** Keys are "app_name/user_id", values are maps of "session_id" to a list of events. */
5152
private final Map<String, Map<String, List<Event>>> sessionEvents;
@@ -91,8 +92,7 @@ public Single<SearchMemoryResponse> searchMemory(String appName, String userId,
9192

9293
Map<String, List<Event>> userSessions = sessionEvents.get(key);
9394

94-
ImmutableSet<String> wordsInQuery =
95-
ImmutableSet.copyOf(query.toLowerCase(Locale.ROOT).split("\\s+"));
95+
ImmutableSet<String> wordsInQuery = extractWordsLower(query);
9696

9797
List<MemoryEntry> matchingMemories = new ArrayList<>();
9898

@@ -105,12 +105,7 @@ public Single<SearchMemoryResponse> searchMemory(String appName, String userId,
105105
Set<String> wordsInEvent = new HashSet<>();
106106
for (Part part : event.content().get().parts().get()) {
107107
String text = part.text().orElse("");
108-
if (!text.isEmpty()) {
109-
Matcher matcher = WORD_PATTERN.matcher(text);
110-
while (matcher.find()) {
111-
wordsInEvent.add(matcher.group().toLowerCase(Locale.ROOT));
112-
}
113-
}
108+
wordsInEvent.addAll(extractWordsLower(text));
114109
}
115110

116111
if (wordsInEvent.isEmpty()) {
@@ -135,6 +130,16 @@ public Single<SearchMemoryResponse> searchMemory(String appName, String userId,
135130
});
136131
}
137132

133+
/** Extracts words from a string and converts them to lowercase. */
134+
private static ImmutableSet<String> extractWordsLower(String text) {
135+
ImmutableSet.Builder<String> words = ImmutableSet.builder();
136+
Matcher matcher = WORD_PATTERN.matcher(text);
137+
while (matcher.find()) {
138+
words.add(matcher.group().toLowerCase(Locale.ROOT));
139+
}
140+
return words.build();
141+
}
142+
138143
private String formatTimestamp(long timestamp) {
139144
return Instant.ofEpochMilli(timestamp).toString();
140145
}

‎core/src/test/java/com/google/adk/memory/InMemoryMemoryServiceTest.java‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,41 @@ public void searchMemory_textAndFunctionCallInOneEvent_stillMatchesOnTheText() {
137137
assertThat(response.memories().get(0).content())
138138
.isEqualTo(Content.fromParts(Part.fromText("weather in Seoul"), functionCall));
139139
}
140+
141+
@Test
142+
public void searchMemory_queryWithPunctuation_matchesWord() {
143+
InMemoryMemoryService service = new InMemoryMemoryService();
144+
service
145+
.addSessionToMemory(sessionWith(event(Part.fromText("weather in Seoul"))))
146+
.blockingAwait();
147+
148+
SearchMemoryResponse response =
149+
service.searchMemory(APP_NAME, USER_ID, "weather?").blockingGet();
150+
151+
assertThat(response.memories()).hasSize(1);
152+
}
153+
154+
@Test
155+
public void searchMemory_nonAsciiWord_matchesWholeWord() {
156+
InMemoryMemoryService service = new InMemoryMemoryService();
157+
service
158+
.addSessionToMemory(sessionWith(event(Part.fromText("Meet me at the café"))))
159+
.blockingAwait();
160+
161+
SearchMemoryResponse response = service.searchMemory(APP_NAME, USER_ID, "café").blockingGet();
162+
163+
assertThat(response.memories()).hasSize(1);
164+
}
165+
166+
@Test
167+
public void searchMemory_digits_matchWord() {
168+
InMemoryMemoryService service = new InMemoryMemoryService();
169+
service
170+
.addSessionToMemory(sessionWith(event(Part.fromText("Order 12345 shipped"))))
171+
.blockingAwait();
172+
173+
SearchMemoryResponse response = service.searchMemory(APP_NAME, USER_ID, "12345").blockingGet();
174+
175+
assertThat(response.memories()).hasSize(1);
176+
}
140177
}

0 commit comments

Comments
 (0)