Skip to content

docs(examples): sync python demo summary#1348

Closed
haosenwang1018 wants to merge 8 commits into
MemMachine:mainfrom
haosenwang1018:docs/examples-readme-python-demo-sync
Closed

docs(examples): sync python demo summary#1348
haosenwang1018 wants to merge 8 commits into
MemMachine:mainfrom
haosenwang1018:docs/examples-readme-python-demo-sync

Conversation

@haosenwang1018

@haosenwang1018 haosenwang1018 commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Purpose of the change

Keep the examples index page aligned with the current Python client demo behavior.

Description

Follow-up to #973 / #1305 / #1307

This updates examples/README.md so the summary for memmachine_client_demo.py reflects the current example semantics:

  • search results are represented as typed SearchResult objects
  • filtered search examples use metadata-prefixed filter keys

This keeps the top-level examples index consistent with the demo file that was updated in recent follow-up PRs.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g., code style improvements, linting)
  • Documentation update
  • Project Maintenance (updates to build scripts, CI, etc., that do not affect the main project)
  • Security (improves security without changing functionality)

How Has This Been Tested?

  • Unit Test
  • Integration Test
  • End-to-end Test
  • Test Script (please provide)
  • Manual verification (list step-by-step instructions)

Manual verification:

  1. Verified the examples index now mentions typed SearchResult usage for the Python client demo
  2. Verified the summary now mentions metadata-prefixed filter examples
  3. Verified the change stays scoped to examples/README.md

Checklist

  • I have signed the commit(s) within this pull request
  • My code follows the style guidelines of this project (See STYLE_GUIDE.md)
  • I have performed a self-review of my own code
  • I have commented my code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

  • Confirmed all checks passed
  • Contributor has signed the commit(s)
  • Reviewed the code
  • Run, Tested, and Verified the change(s) work as expected

@sscargal sscargal requested a review from Copilot April 17, 2026 16:52
@sscargal

Copy link
Copy Markdown
Contributor

@haosenwang1018 Thanks for this PR. Please sign your commits, which is a requirement for merging. See section 3.5 of the CONTRIBUTING guide. Thanks.

Copilot AI left a comment

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.

Pull request overview

Updates the Python client, LangGraph integration, and documentation/examples to align with the current v2 API filtering semantics and typed response models.

Changes:

  • Add optional raw filter string support to Python client Memory.search() and Memory.list() and pass it through LangGraph tools.
  • Update docs/examples to describe typed SearchResult usage and metadata-prefixed filter keys.
  • Update/extend client tests for raw filter string handling and metadata-prefixed filter dict keys.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/client/src/memmachine_client/memory.py Adds raw filter string support and combines it with built-in + filter_dict filters.
packages/client/src/memmachine_client/langgraph.py Adds episode_type passthrough/normalization and raw filter passthrough for searches.
packages/client/client_tests/test_memory.py Adds tests for raw filter string behavior; updates some filter-string expectations.
packages/client/client_tests/test_langgraph.py Updates tests for new episode_type param and raw filter passthrough.
packages/client/client_tests/test_integration_complete.py Updates integration test filter dict to use metadata. prefix.
packages/client/README.md Updates Python usage snippets to typed results and metadata-prefixed filters.
examples/memmachine_client_demo.py Updates demo printing and filter dict examples to typed results + metadata-prefixed filters.
examples/README.md Updates examples index description for the Python demo.
docs/api_reference/python/client.mdx Updates docs snippet to typed accessors for search results.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 369 to 372
*,
filter: str | None = None,
set_metadata: dict[str, JsonValue] | None = None,
agent_mode: bool = False,

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

The PR description/title indicates this is a docs-only sync for the examples index, but this change introduces new public client API surface (filter raw string parameter). Please either update the PR description to reflect the behavioral/API changes, or split the docs-only update from the client API change to keep review/rollout risk clear.

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +49
episodic_memories = results.episodic_memory or []
if not episodic_memories:
print(" No memories found.")
return

episodic_memories = results["episodic_memory"]
if episodic_memories and len(episodic_memories) > 0:
print(f" Found {len(episodic_memories[0])} relevant memories:")
for i, memory in enumerate(episodic_memories[0][:3], 1): # Show top 3
print(f" Time: {memory['timestamp']}")
print(f" {i}. {memory['content']}")
if memory.get("user_metadata"):
print(f" Metadata: {memory['user_metadata']}")
print()
print(f" Found {len(episodic_memories)} relevant memories:")
for i, memory in enumerate(episodic_memories[:3], 1): # Show top 3
print(f" Time: {memory.timestamp}")
print(f" {i}. {memory.content}")
if memory.user_metadata:
print(f" Metadata: {memory.user_metadata}")

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

memory.search() returns a SearchResult whose episodic/semantic payloads live under results.content (per memmachine_common.api.spec.SearchResult). Accessing results.episodic_memory and treating it as a flat list will raise AttributeError, and EpisodeResponse fields are created_at/metadata (not timestamp/user_metadata). Update this helper to pull episodes from results.content.episodic_memory.{short_term_memory,long_term_memory}.episodes and print the correct fields.

Copilot uses AI. Check for mistakes.
Comment thread packages/client/README.md
Comment on lines +109 to 114
print(f"Episodic memory: {results.episodic_memory or []}")
print(f"Semantic memory: {results.semantic_memory or []}")

# Search with filters
work_results = memory.search("Tell me about work", filter_dict={"category": "work"})
work_results = memory.search("Tell me about work", filter_dict={"metadata.category": "work"})
print(f"Work results: {work_results}")

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

This README example uses results.episodic_memory / results.semantic_memory, but the Python client returns a SearchResult with these fields under results.content (SearchResultContent.episodic_memory / .semantic_memory). As written, the snippet will raise AttributeError. Update the example to access results.content and, for episodic, iterate the episode lists inside the short/long-term containers.

Copilot uses AI. Check for mistakes.
print("Results found:")
for idx, item in enumerate(results.get('episodic_memory', [])):
print(f"[{idx+1}] {item['content']} (Role: {item['producer_role']})")
for idx, item in enumerate(results.episodic_memory or []):

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

This snippet iterates results.episodic_memory, but SearchResult models store results under results.content.episodic_memory (and episodic results are nested under short/long-term memory, not a flat list). As written it will fail at runtime. Adjust the docs example to extract the episode list(s) from results.content.episodic_memory before iterating.

Suggested change
for idx, item in enumerate(results.episodic_memory or []):
episodes = []
episodic_memory = results.content.episodic_memory if results.content else None
if episodic_memory:
episodes.extend(episodic_memory.short_term or [])
episodes.extend(episodic_memory.long_term or [])
for idx, item in enumerate(episodes):

Copilot uses AI. Check for mistakes.
Comment on lines 463 to 464
assert "category='work'" in json_data["filter"]
assert call_args[1]["timeout"] == 15

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

This assertion expects an unprefixed category='work' filter to be sent. Given the server-side filter normalization only treats user metadata as user metadata when prefixed with metadata. or m., an unprefixed category field is likely treated as an unknown system field (and ignored / rejected depending on server version). Consider updating this backward-compat positional-args test to use metadata.category (and update the asserted substring) so it reflects the current filter semantics.

Copilot uses AI. Check for mistakes.
Comment on lines 384 to 389
def add_memory_tool(
content: str,
user_id: str | None = None,
metadata: dict[str, Any] | None = None,
episode_type: EpisodeType | str | None = None,
) -> dict[str, Any]:

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

create_add_memory_tool's return type annotation still describes a 3-argument callable, but add_memory_tool now accepts a 4th episode_type parameter. Please update the Callable[[...]] type signature (and any related docs) to match the actual tool function signature so type checkers/users don't get incorrect guidance.

Copilot uses AI. Check for mistakes.
Comment on lines 459 to 468
def list(
self,
memory_type: MemoryType = MemoryType.Episodic,
page_size: int = 100,
page_num: int = 0,
filter_dict: dict[str, str] | None = None,
filter: str | None = None,
set_metadata: dict[str, JsonValue] | None = None,
timeout: int | None = None,
) -> ListResult:

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

list() adds a new positional parameter (filter) between filter_dict and set_metadata, which can silently break any callers passing set_metadata/timeout positionally (their dict/int would be interpreted as the raw filter string). To preserve backward compatibility, make filter keyword-only (e.g., move it after a * or place it after timeout as a kw-only arg) or append it at the end without changing existing positional ordering.

Copilot uses AI. Check for mistakes.
@SarahScargall

Copy link
Copy Markdown
Contributor

Hi @haosenwang1018!

For this PR (and all your other PRs) to merge, we need you to sign your commits.

Also, please review the feedback CoPilot has generated and respond accordingly. Conflicts are especially important to respond to.

Kind Regards,
Sarah

@SarahScargall SarahScargall self-requested a review May 4, 2026 18:46
@sscargal sscargal added this to the v0.3.9 milestone May 13, 2026
sscargal added a commit to sscargal/MemMachine that referenced this pull request May 13, 2026
Add three small features to the Python client and its LangGraph wrapper
so callers can pass structured filter expressions and either-enum-or-string
episode types directly.

1. `Memory.search(filter=...)` and `Memory.list(filter=...)`
   Accept an optional raw filter string alongside `filter_dict`. When both
   are provided, the two are combined with `AND`. The raw filter is passed
   through to the v2 `SearchMemoriesSpec.filter` / `ListMemoriesSpec.filter`
   fields unchanged.

2. `MemMachineTools.search_memory(filter=...)`
   Pipes the same raw filter through the LangGraph search-memory tool.

3. `MemMachineTools.add_memory(episode_type=...)`
   Accept either an `EpisodeType` enum or its string value
   (e.g. `"message"`), normalizing strings via `EpisodeType(...)` before
   delegating to `Memory.add`. The factory tool's return-type annotation
   was widened to match.

The `filter` parameter shadows the Python builtin, which is the same
trade-off `memmachine_common.api.SearchMemoriesSpec` already made for
its `filter:` field — keeping the parameter name aligned with the API
field. `# noqa: A002` is applied at the three call sites with a comment
pointing at the API spec.

This commit consolidates the substantive work from haosenwang1018's
9-commit stack (MemMachine#1341MemMachine#1349) into a single rebased+linted commit
against current `main`. The original stack's prefix-style doc and test
changes have been omitted because they have already landed on `main`
via MemMachine#1352 and MemMachine#1311. The original commits authored by haosenwang1018:

  - 921b55f feat(client): support raw filter strings
  - e0849bb feat(langgraph): support raw filter strings
  - 53b489e fix(langgraph): normalize episode type strings

Closes MemMachine#1341, MemMachine#1342, MemMachine#1343, MemMachine#1344, MemMachine#1345, MemMachine#1346, MemMachine#1347, MemMachine#1348, MemMachine#1349

Co-authored-by: Steve Scargall <steve.scargall@gmail.com>
Signed-off-by: Steve Scargall <37674041+sscargal@users.noreply.github.com>
malatewang added a commit that referenced this pull request May 13, 2026
…ion (#1403)

* feat(client+langgraph): raw filter strings and EpisodeType normalization

Add three small features to the Python client and its LangGraph wrapper
so callers can pass structured filter expressions and either-enum-or-string
episode types directly.

1. `Memory.search(filter=...)` and `Memory.list(filter=...)`
   Accept an optional raw filter string alongside `filter_dict`. When both
   are provided, the two are combined with `AND`. The raw filter is passed
   through to the v2 `SearchMemoriesSpec.filter` / `ListMemoriesSpec.filter`
   fields unchanged.

2. `MemMachineTools.search_memory(filter=...)`
   Pipes the same raw filter through the LangGraph search-memory tool.

3. `MemMachineTools.add_memory(episode_type=...)`
   Accept either an `EpisodeType` enum or its string value
   (e.g. `"message"`), normalizing strings via `EpisodeType(...)` before
   delegating to `Memory.add`. The factory tool's return-type annotation
   was widened to match.

The `filter` parameter shadows the Python builtin, which is the same
trade-off `memmachine_common.api.SearchMemoriesSpec` already made for
its `filter:` field — keeping the parameter name aligned with the API
field. `# noqa: A002` is applied at the three call sites with a comment
pointing at the API spec.

This commit consolidates the substantive work from haosenwang1018's
9-commit stack (#1341#1349) into a single rebased+linted commit
against current `main`. The original stack's prefix-style doc and test
changes have been omitted because they have already landed on `main`
via #1352 and #1311. The original commits authored by haosenwang1018:

  - 921b55f feat(client): support raw filter strings
  - e0849bb feat(langgraph): support raw filter strings
  - 53b489e fix(langgraph): normalize episode type strings

Closes #1341, #1342, #1343, #1344, #1345, #1346, #1347, #1348, #1349

Co-authored-by: Steve Scargall <steve.scargall@gmail.com>
Signed-off-by: Steve Scargall <37674041+sscargal@users.noreply.github.com>

* docs(langgraph): document filter and episode type support

---------

Signed-off-by: Steve Scargall <37674041+sscargal@users.noreply.github.com>
Co-authored-by: haosenwang1018 <haosenwang1018@users.noreply.github.com>
Co-authored-by: Shu Wang <33640803+malatewang@users.noreply.github.com>
@sscargal

Copy link
Copy Markdown
Contributor

Closed by #1403

@sscargal sscargal closed this May 13, 2026
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.

4 participants