Repository navigation
FIX: Reject non-dictionary metadata before conversation updates - #3917
Open
YingzuoLiu wants to merge 2 commits into
Open
YingzuoLiu wants to merge 2 commits into
YingzuoLiu wants to merge 2 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues were identified for the conversation metadata validation change.
No open issues 🎉
What changed in this PR
Addresses #3910 by rejecting non-dictionary metadata before the dedicated conversation metadata replacement API writes to storage, preventing invalid metadata from breaking message retrieval.
Changes:
- Adds validation in the shared execution helper, covering both asynchronous and deprecated synchronous entry points.
- Preserves valid dictionaries, nested values, and generic raw-column update behavior.
- Adds regression tests for invalid roots, unchanged message data, valid replacements, and persistence across separate-process database reopening.
| File | Description |
|---|---|
tests/unit/memory/test_sqlite_memory.py |
Adds metadata validation and database-reopening regression tests. |
pyrit/memory/memory_interface.py |
Rejects non-dictionary metadata with ValueError before dispatching updates. |
Review effort: Balanced
Call the public synchronous API directly and assert its deprecation warning, rejection of an invalid root, and preservation of the stored message. Validation: 9 metadata replacement tests passed; SQLite/Azure unit suites 198 passed, 1 skipped. Ruff check/format, scoped ty and diff check passed. AI assistance: OpenAI Codex implemented and validated this follow-up under the account owner's authorization.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #3910.
The dedicated metadata replacement API accepts dynamically typed non-dictionary JSON roots, commits them, and returns success. Reading those messages then raises a Pydantic validation error. Reject non-dictionary roots with
ValueErrorin the shared execution helper before dispatching a write. Generic raw-column updates and nested dictionary values retain their existing behavior.Both built-in public entry points use this helper: the deprecated synchronous method calls it directly; the asynchronous method passes it to
_run_database_operation_async. The regression suite now calls the synchronous public method directly and checks its deprecation warning, invalid-root rejection, and preservation of the stored message.Tests and Documentation
Rerun on 2026-11-04 against current PR head
847854bff64e7873b21ee0e9d64bc79b1f14dd6a. Verified the tested source and test files match that remote commit. Baseline is main77b88f5385311c0f89a935aae0de61eb4caf9fda, in a separate worktree with the same nine regression cases copied in.python -m pytest tests/unit/memory/test_sqlite_memory.py -k metadata_replacement -q: baseline 6 failed, 3 passed; current head 9 passed. These are actual rerun results, including the new synchronous-entry case.python -m pytest tests/unit/memory/test_sqlite_memory.py tests/unit/memory/test_azure_sql_memory.py -q: current head 198 passed, 1 skipped.ty check, andgit diff --checkpassed on rerun. The repository'scheck_no_rest_rolesandcheck_async_suffixchecks passed during the original implementation validation.Coverage includes list/string/null/integer roots, preservation of multiple pieces, empty/nonempty/nested dictionaries, unrelated and missing conversations, the deprecated synchronous entry, and file-database reopening in a separate Python process.
Reopen test control flow: the
if sys.argv[2] == "write":block only inserts messages and verifies rejection. Thepieces = await memory.get_message_pieces_async(...)assignment and all three following assertions are after and outside that block, inside the commontrybody. Both modes therefore check two messages, their original values, and their original metadata. This was rechecked in the source and Python AST; read mode does not skip validation.Caller audit: repository-wide search plus an AST audit of calls in
pyrit,tests, anddocfound no caller usingprompt_metadata=Noneto clear metadata, apart from the intentional invalid-input regression. Existing non-regression call sites pass dictionaries. Empty-dictionary replacement remains supported and tested. This does not assert anything about external callers.Azure SQL coverage uses the repository's unit-test doubles; no live Azure SQL, external inference, full optional-dependency suite, or full CI is claimed. Local SOCKS proxy support required installing
socksio; repository dependency files are unchanged. No notebooks changed; JupyText was not run.CI at the latest check (2026-11-04):
license/clasucceeded. Six workflows reportaction_requiredand await maintainer approval to run; full CI is not yet green.AI assistance
OpenAI Codex performed source inspection, reproduction, implementation, and local validation under the account owner's authorization.