Skip to content

fix(cli): preserve SQLite session URI options - #8010

Open
feiiiiii5 wants to merge 3 commits into
google:mainfrom
feiiiiii5:codex/sqlite-session-uri-options
Open

feiiiiii5 wants to merge 3 commits into
google:mainfrom
feiiiiii5:codex/sqlite-session-uri-options

Conversation

@feiiiiii5

Copy link
Copy Markdown
Contributor

Link to Issue or Description of Change

Problem: The CLI/Web SQLite session factory extracts only the URI path. A ?mode=ro database is opened writable, and an encoded filename can open a different database.

Solution: Pass the original URI to SqliteSessionService, whose existing parser already handles path decoding and SQLite query options. Keep the no-path in-memory case.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally. See the matrix notes below.

The two new tests use real SQLite files through the registry. Both fail on main (read-only writes succeed; the encoded path misses the saved session). Registry, service-factory and session tests: 866 passed, 1 xfailed. Pre-commit and targeted mypy pass.

Manual End-to-End (E2E) Tests:

Used create_session_service_from_options with temporary databases: the encoded URI reads the saved count=1; the plain URI with ?mode=ro reads it and rejects a write with OperationalError: attempt to write a readonly database.

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. See below.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Full tox matrix

Python 3.11: 23,598 passed; one dependency-version self-check failed because my initial local lock selected OTel 1.45.1. After updating the ignored local lock to the required 1.45.2, that check and the related suites passed (867 passed, 1 xfailed).

Python 3.12: 23,589 passed; one untouched telemetry timing test measured 0.161867s against a 0.10±0.05s bound. The same node then passed independently on both main and this branch with the same dependencies; its test and implementation files are identical between them.

Python 3.13: 23,590 passed, 116 skipped, 12 xfailed, 2 xpassed; tox passed.

Python 3.14: 23,592 passed, 114 skipped, 12 xfailed, 2 xpassed; tox passed.

No tracked dependency or lock files changed.

list(ignored_kwargs.keys()),
)
return SqliteSessionService(db_path=db_path)
return SqliteSessionService(db_path=uri)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passing the raw URI through still breaks once the encoded path and an option show up together: sqlite:///sessions%20%231.db?mode=ro turns into file:sessions #1.db?mode=ro in _parse_db_path, sqlite reads the # as the end of the path, so it quietly creates and opens a new writable db called sessions (the session lookup returns None and mode=ro is gone). re-encoding the path there fixes it, and _sqlite_memory_service._parse_db_path needs the same line:

--- a/src/google/adk/sessions/sqlite_session_service.py
+++ b/src/google/adk/sessions/sqlite_session_service.py
@@ -24,6 +24,7 @@ import os
 import sqlite3
 from typing import Any
 from typing import cast
+from urllib.parse import quote
 from urllib.parse import unquote
 from urllib.parse import urlparse

@@ -177,7 +178,10 @@ def _parse_db_path(db_path: str) -> tuple[str, str, bool]:

   if parsed.query:
     # sqlite3 only treats the filename as a URI when it starts with `file:`.
-    return normalized_path, f"file:{normalized_path}?{parsed.query}", True
+    # Re-encode the decoded path, or a `#` or `?` in the filename would end
+    # the path early and drop the query options.
+    connect_uri = f"file:{quote(normalized_path)}?{parsed.query}"
+    return normalized_path, connect_uri, True

   return normalized_path, normalized_path, False

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in bb24f03: both _parse_db_path implementations now build the connect URI as file:{quote(normalized_path)}?{query}, so #, ? and a literal % in the decoded filename no longer truncate the path or drop mode=ro. The regressions are extended across reserved characters (#, ?, %23, +&= ü), relative and absolute paths, and no-query / ro / rw modes.

Verified on the branch: the two affected suites (tests/unittests/cli/test_service_registry.py, tests/unittests/memory/test_sqlite_memory_service.py) are 36 failed / 164 passed with the parent source for those two files swapped in, and 200 passed at bb24f03 (Python 3.12). Not run: the full tox matrix and Windows.

@its-amann

Copy link
Copy Markdown
Contributor

thanks for applying my fix in bb24f03! could you add a Co-authored-by: Aman Agnihotri <amanagnihotri902@gmail.com> trailer to that commit so it counts for me too

Quote the decoded path before building file: URIs in session and memory services. Otherwise # or ? truncates the filename and drops mode=ro, while literal percent escapes select a different database.

Extend public-service regressions across reserved characters, relative and absolute paths, and no-query/read-only/read-write modes. The original head fails 36 cases with 54 passing controls; the fix passes all 90. Affected session, registry, factory and SQLite memory suites: 1039 passed, 1 xfailed on Linux/Python 3.12.14. Changed-file pre-commit and targeted mypy pass. Full tox and Windows were not run.

Co-authored-by: Aman Agnihotri <amanagnihotri902@gmail.com>
@feiiiiii5
feiiiiii5 force-pushed the codex/sqlite-session-uri-options branch from bb24f03 to a66dda7 Compare November 9, 2026 09:59
@feiiiiii5

Copy link
Copy Markdown
Contributor Author

Added the Co-authored-by: Aman Agnihotri <amanagnihotri902@gmail.com> trailer to the tip commit and updated the branch head to a66dda73. The PR should pick up the new head and rerun checks.

@feiiiiii5

Copy link
Copy Markdown
Contributor Author

Heads-up: after adding the trailer, cla/google now reports the co-author amanagnihotri902@gmail.com as not covered (the PR author is covered). If that is you, signing at https://cla.developers.google.com/ and then using the check's "New Contributors" rescan link should clear it. I kept the trailer as requested.

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.

3 participants