Skip to content

fix(memory): match a Latin word embedded in unspaced-script text - #6773

Open
LHMQ878 wants to merge 1 commit into
google:mainfrom
LHMQ878:fix/memory-search-latin-in-unspaced-script
Open

fix(memory): match a Latin word embedded in unspaced-script text#6773
LHMQ878 wants to merge 1 commit into
google:mainfrom
LHMQ878:fix/memory-search-latin-in-unspaced-script

Conversation

@LHMQ878

@LHMQ878 LHMQ878 commented Aug 17, 2026

Copy link
Copy Markdown

Link to Issue or Description of Change

Related: #5501 (same code path, the Latin-word half of the problem was left open)

Problem:

InMemoryMemoryService.search_memory tokenizes an event with re.findall(r'\w+', text). Japanese and Chinese are written without spaces, so a whole sentence comes back as a single token: 私はPythonでADKを使っています tokenizes to {'私はpythonでadkを使っています'}.

The Unicode fix in b8ea1e8 handles a non-Latin query by also matching it as a substring of the event text, but a Latin query word is still only matched against whole tokens. So a Latin word embedded in unspaced-script text is unreachable — which is exactly how Japanese/Chinese users write about code, product names and identifiers:

TEXT = "私はPythonでADKを使っています"   # "I use ADK with Python"

# on main
query='Python'   hits=0
query='ADK'      hits=0
query='使って'   hits=1   # non-Latin query works (substring fallback)

Solution:

Index an event token that mixes scripts by its ASCII and non-ASCII runs as well as by the token itself (new _extract_searchable_words), so 私はpythonでadkを使っています also yields 私は, python, , adk, を使っています.

This makes the embedded Latin word a token of its own and is matched exactly, so the partial-word guard the existing tests assert ('thon' must not match Python) still holds — a plain "substring-match Latin words too" fallback would have broken it. Pure-ASCII text produces the same token set as before, so ranking and result bounding are unchanged. Only the event side is affected; query tokenization is untouched, so the match counts used for ranking stay one-per-query-word.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added six cases to the existing test_search_memory_non_latin parametrization — three that fail on main and three guards:

event text query expected
私はPythonでADKを使っています Python 1 (fails on main)
私はPythonでADKを使っています adk 1 (fails on main)
我用Python写代码 python 1 (fails on main)
私はPythonでADKを使っています 使って 1 (non-Latin substring still works)
私はPythonでADKを使っています Java 0 (no false positive)
私はPythonでADKを使っています thon 0 (partial Latin word still must not match)

On main, the three new positives fail:

FAILED tests/unittests/memory/test_in_memory_memory_service.py::test_search_memory_non_latin[私はPythonでADKを使っています-Python-1]
FAILED tests/unittests/memory/test_in_memory_memory_service.py::test_search_memory_non_latin[私はPythonでADKを使っています-adk-1]
FAILED tests/unittests/memory/test_in_memory_memory_service.py::test_search_memory_non_latin[我用Python写代码-python-1]
3 failed, 12 passed

With the change:

$ pytest tests/unittests/memory/ -q -p no:randomly
92 passed, 2 warnings in 36.15s

$ pytest tests/unittests/tools/test_preload_memory_tool.py -q -p no:randomly
4 passed

$ pytest tests/unittests/tools/test_agent_tool.py \
         tests/unittests/flows/llm_flows/test_agent_transfer_system_instructions.py \
         tests/unittests/cli/test_service_registry.py \
         tests/unittests/cli/utils/test_service_factory.py -q -p no:randomly
106 passed, 1 skipped

pre-commit run --files <changed files> passes (isort, pyink, ruff, addlicense, codespell, ADK compliance checks).

Manual End-to-End (E2E) Tests:

Same store, searched before and after the change:

svc = InMemoryMemoryService()
await svc.add_session_to_memory(session_with_one_event("私はPythonでADKを使っています"))
for q in ["Python", "ADK", "使って", "thon", "Java"]:
    print(q, len((await svc.search_memory(app_name="app", user_id="u", query=q)).memories))
query before after
Python 0 1
ADK 0 1
使って 1 1
thon 0 0
Java 0 0

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

InMemoryMemoryService tokenizes an event with \w+, which cannot split a script
that writes without spaces, so 私はPythonでADKを使っています comes back as a
single token. A non-Latin query word is matched as a substring of the event
text, but a Latin one is matched only against whole tokens, so searching that
event for "Python" or "ADK" returned nothing.

An event token that mixes scripts is now also indexed by its ASCII and
non-ASCII runs, which makes the embedded Latin word a token of its own while
still keeping a partial word such as "thon" from matching.

Related: google#5501
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants