Repository navigation
SqliteMemoryService can't find a stored word that starts with a capital dotted I (İ) #7540
Description
🔴 Required Information
Describe the Bug:
SqliteMemoryService stores an event with the text "İstanbul trip". Searching for "İstanbul" returns nothing. Same in FTS mode and LIKE mode. Any word with a capital dotted I is affected, so most Turkish and Azerbaijani text with a capitalized İ can't be found by that word.
Steps to Reproduce:
pip install google-adk(or a checkout of main)- Save the script below as
repro.py - Run
python repro.py
Expected Behavior:
Searching for "İstanbul" returns the event, like searching for "trip" does.
Observed Behavior:
fts=on query='İstanbul' hits=0
fts=on query='trip' hits=1
fts=off query='İstanbul' hits=0
fts=off query='trip' hits=1
Environment Details:
- ADK Library Version (pip show google-adk): 2.12.0, main at 29bb053
- Desktop OS: macOS 26.6
- Python Version (python -V): Python 3.12.13 (SQLite 3.53.4)
Model Information:
- Are you using LiteLLM: No
- Which model is being used: N/A, no model call needed
🟡 Optional Information
Regression:
No. It has been there since SqliteMemoryService was added in 9625b06.
Root cause:
Indexing and querying normalize text in a different order.
- When it stores an event,
add_events_to_memorylowercases first and then calls_split_script_runs(src/google/adk/memory/_sqlite_memory_service.py:329-330). - When it searches,
_extract_tokenscalls_split_script_runsfirst and lowercases each token after (_sqlite_memory_service.py:531-535).
In Python, "İ".lower() is two characters: "i" and U+0307 COMBINING DOT ABOVE. U+0307's Unicode name doesn't start with LATIN, so _is_latin (_sqlite_memory_service.py:510-513) returns False for it and _split_script_runs cuts the word there. "İstanbul" gets indexed as "i ̇ stanbul", while the query token is "i̇stanbul". Neither FTS nor LIKE can match the two.
I checked every code point: U+0130 is the only Latin character whose lowercase contains a non-Latin character, so this is the only letter hit.
Minimal Reproduction Code:
import asyncio
from google.adk.events.event import Event
from google.adk.memory import SqliteMemoryService
from google.genai import types
async def main() -> None:
for fts in ("on", "off"):
service = SqliteMemoryService(":memory:", fts=fts)
await service.add_events_to_memory(
app_name="app",
user_id="user",
session_id="s1",
events=[
Event(
id="e1",
author="user",
timestamp=1.0,
content=types.Content(
role="user", parts=[types.Part(text="İstanbul trip")]
),
)
],
)
for query in ("İstanbul", "trip"):
response = await service.search_memory(
app_name="app", user_id="user", query=query
)
print(f"fts={fts} query={query!r} hits={len(response.memories)}")
await service.close()
asyncio.run(main())How often has this issue occurred?:
- Always (100%)
I have a fix with a regression test ready and will open a PR.
Activity
surajksharma07 commentedon Oct 15, 2026
@Somay-kousis Reproduced this on main (2.12.0) on Windows/SQLite 3.45 too so it isn't platform specific.
Your reorder in #7541 fixes it on my side in both FTS and LIKE mode and the existing memory tests still pass. For anyone stuck on 2.11/2.12 meanwhile patching _is_latin to also accept "̇" works as a stopgap.
One thing worth calling out: rows indexed before the fix stay unsearchable until re-added so a short note in the PR description would help.
Could you also give it a quick run with some mixed-script text (Turkish + CJK/Hindi) to be sure nothing else shifts? Once that looks good we'll push #7541 for review.
Somay-kousis commentedon Oct 15, 2026
Thanks for checking it on Windows.
Ran a mixed-script check on main and on #7541: 8 stored events mixing Turkish (İ, ı), CJK, Hindi, Cyrillic and accented Latin, 25 queries, FTS and LIKE mode.
İzmirin "İzmir और दिल्ली की यात्रा" goes from 0 to 1.İstanbulin "東京İstanbul直行便" now matches in both modes. In FTS modeistanbulandincefind them too.istanbulstill won't match "İstanbul". Same on main.The note about rows indexed before the fix is in the PR description, under Solution.
surajksharma07 commentedon Oct 15, 2026
Matches what I see @Somay-kousis. On 9706f50 I get 48/48 in test_sqlite_memory_service.py and a mixed Turkish/CJK/Hindi/Cyrillic run only changes the İ hits, same as yours.
Small nit for the description: scanned every code point and U+2183 (Ↄ) also indexes differently now. Its lowercase is Latin so it gets split off from neighbouring Latin letters. That just matches what the query side already does so "abↃcd" now matches in FTS mode too (0 -> 1). It’s harmless but it means U+0130 isn’t strictly the only one.
Agreed that the LIKE-mode "istanbul" vs "İstanbul" gap is pre-existing and out of scope here, it can be its own issue if anyone hits it.
Nothing else from my side. Will flag #7541 for maintainer review.
Somay-kousis commentedon Oct 15, 2026
Good catch on Ↄ, thanks. I reran a scan over every code point and it finds one more: U+03A3 Σ. Lowercasing the whole string picks final ς when Σ ends a word glued to Latin letters (
abΣbecomesabς), while splitting first givesab σ, which is what the query side already produces. Same as Ↄ, searches only gain hits, and plain Greek words like ΟΔΥΣΣΕΥΣ index the same as before.Updated the PR description to list all three.
surajksharma07 commentedon Oct 15, 2026
Nice find @Somay-kousis, my scan only put each char alone or mid-word so it never hit the word-final σ/ς case. With end-of-word positions added I get exactly the same three: U+0130, U+03A3 and U+2183.
Also checked Σ end to end: storing "abΣ note" and querying Σ/σ goes from 1 to 2 hits in LIKE mode, FTS is unchanged (it already matched) and ΟΔΥΣΣΕΥΣ/οδυσσευς return the same as on main. So it only gains hits as you said.
The code is still the same single commit and the updated description covers everything. All good from my side, #7541 is flagged for maintainer review.
fix: find stored words with a capital dotted I in sqlite memory