Skip to content

[store] Add StoreBundle.from_dict() for symmetric serialization#164

Open
Copilot wants to merge 2 commits intomainfrom
copilot/add-storebundle-from-dict-method
Open

[store] Add StoreBundle.from_dict() for symmetric serialization#164
Copilot wants to merge 2 commits intomainfrom
copilot/add-storebundle-from-dict-method

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

Summary

Closes #66

StoreBundle had to_dict() but no from_dict(), making it the only serializable type in the codebase without a round-trip. InMemoryArtifactStore had the same gap.

Changes

  • InMemoryArtifactStore.from_dict() — restores the metadata index (refs) from a serialized dict. Raw bytes are not JSON-serializable and are explicitly documented as unavailable after round-tripping; only ArtifactRef metadata (handle, media_type, size_bytes, label) is restored.
  • StoreBundle.from_dict() — delegates to each store's from_dict() for non-None entries; absent stores remain None.
  • tests/test_store_artifacts.py — adds 3 tests: metadata restore, empty input, and the metadata-only round-trip contract.
  • tests/test_store_bundle.py (new) — 4 tests: all-None, all-stores, partial-stores, and dict structure.
bundle = StoreBundle(event_log=log, fact_store=facts)
restored = StoreBundle.from_dict(bundle.to_dict())
# restored.event_log and restored.fact_store are populated;
# restored.artifact_store and restored.episodic_store are None

Checklist

  • Tests added or updated for every new/changed public function
  • make ci passes locally (fmt + lint + type + test + example + demo)
  • CHANGELOG.md updated under ## [Unreleased]
  • Docstrings added for all new public APIs (Google-style)
  • Every modified module stays ≤ 300 lines (or a decomposition issue is linked above)
  • Related issue linked in the summary above
  • Agent-facing docs updated if pipeline, API, or conventions changed

Notes for reviewers

InMemoryArtifactStore.from_dict() only restores the metadata index — the _data dict (raw bytes) is intentionally left empty. This matches what to_dict() serializes (refs only) and is documented in the docstring. Callers that need byte contents must repopulate via put() after loading.

The typing note from the issue (protocol types for StoreBundle fields) is deferred pending #40.

… symmetric serialization

Agent-Logs-Url: https://github.com/dgenio/contextweaver/sessions/899c9875-0eb9-4fca-937a-024fae9c064b

Co-authored-by: dgenio <12731907+dgenio@users.noreply.github.com>
Copilot AI changed the title [WIP] Add StoreBundle.from_dict() for symmetric serialization [store] Add StoreBundle.from_dict() for symmetric serialization Apr 14, 2026
Copilot AI requested a review from dgenio April 14, 2026 09:01
@dgenio dgenio marked this pull request as ready for review April 14, 2026 09:23
@dgenio dgenio requested review from Copilot April 14, 2026 09:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds symmetric JSON-compatible deserialization for the store layer by introducing from_dict() round-tripping for StoreBundle and InMemoryArtifactStore (metadata-only for artifacts), with accompanying unit tests.

Changes:

  • Add InMemoryArtifactStore.from_dict() to restore the artifact metadata index (ArtifactRefs) from serialized data.
  • Add StoreBundle.from_dict() to reconstruct non-None stores from StoreBundle.to_dict() output.
  • Add/extend tests to validate round-trip behavior and the “metadata-only” artifact contract.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/contextweaver/store/artifacts.py Implements InMemoryArtifactStore.from_dict() restoring refs metadata only.
src/contextweaver/store/__init__.py Adds StoreBundle.from_dict() to rebuild bundles from serialized dicts.
tests/test_store_artifacts.py Adds tests for artifact metadata restoration and metadata-only round-trip semantics.
tests/test_store_bundle.py New tests covering StoreBundle round-tripping across all/partial/none store configurations.

Comment on lines +40 to +43
@classmethod
def from_dict(cls, data: dict[str, Any]) -> StoreBundle:
"""Deserialise from a JSON-compatible dict produced by :meth:`to_dict`."""
raw_artifact = data.get("artifact_store")
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This PR introduces new public from_dict() APIs (on StoreBundle and InMemoryArtifactStore). Per the project workflow, public API additions should be recorded under CHANGELOG.md## [Unreleased] so downstream users can discover the new serialization support.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +60
@classmethod
def from_dict(cls, data: dict[str, Any]) -> StoreBundle:
"""Deserialise from a JSON-compatible dict produced by :meth:`to_dict`."""
raw_artifact = data.get("artifact_store")
raw_event_log = data.get("event_log")
raw_episodic = data.get("episodic_store")
raw_fact = data.get("fact_store")
return cls(
artifact_store=InMemoryArtifactStore.from_dict(raw_artifact)
if raw_artifact is not None
else None,
event_log=InMemoryEventLog.from_dict(raw_event_log)
if raw_event_log is not None
else None,
episodic_store=InMemoryEpisodicStore.from_dict(raw_episodic)
if raw_episodic is not None
else None,
fact_store=InMemoryFactStore.from_dict(raw_fact)
if raw_fact is not None
else None,
)
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

StoreBundle.from_dict() adds additional implementation logic to src/contextweaver/store/__init__.py, but the repo hard rule is that __init__.py files should contain re-exports only (no business logic). Consider moving StoreBundle (and its to_dict/from_dict) into a dedicated module (e.g., store/bundle.py) and re-exporting it from store/__init__.py to comply with that rule and avoid import-side effects growing over time.

Copilot uses AI. Check for mistakes.
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.

[store] Add StoreBundle.from_dict() for symmetric serialization

3 participants