-
Notifications
You must be signed in to change notification settings - Fork 17
Engram docs #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Engram docs #345
Changes from 12 commits
301bac7
bc28bd0
1b934bb
a129d89
8157717
bd35628
cbde720
6ba99c6
d8469d5
4c90794
11e3181
567503c
4e54443
4ed4952
165cda3
85f9cab
f398fad
70a714d
0a69c5a
ff9a955
5f40a64
fc28b39
4c6bac3
c4f56a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import os | ||
| import time | ||
| import uuid | ||
| from engram import EngramClient | ||
|
|
||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
|
|
||
| test_user_id = f"test-{uuid.uuid4().hex[:8]}" | ||
|
|
||
| # Setup: store a memory to get a run_id | ||
| run = client.memories.add( | ||
| "The user prefers dark mode", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
|
|
||
| # START PollRun | ||
| status = client.runs.wait(run.run_id) | ||
|
|
||
| print(status.run_id) | ||
| print(status.status) | ||
| print(status.committed_operations) | ||
| # END PollRun | ||
|
|
||
| assert status.status == "completed" | ||
| assert status.committed_operations is not None | ||
| assert len(status.memories_created) >= 1 | ||
|
|
||
| time.sleep(2) # Allow tenant indexing to complete | ||
|
|
||
| # Cleanup | ||
| _all = client.memories.search(query="dark mode", user_id=test_user_id, group="default") | ||
| for _m in _all: | ||
| client.memories.delete(_m.id, user_id=test_user_id, group="default") | ||
|
|
||
| client.close() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import os | ||
| from engram import EngramClient | ||
|
|
||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
|
|
||
| user_id = os.environ.get("ENGRAM_USER_ID", "user-uuid") | ||
| group = os.environ.get("ENGRAM_GROUP", "default") | ||
|
|
||
| deleted = 0 | ||
| for _ in range(20): | ||
| results = client.memories.search(query="user", user_id=user_id, group=group) | ||
| if len(results) == 0: | ||
| break | ||
| for m in results: | ||
| try: | ||
| client.memories.delete(m.id, topic=m.topic, user_id=user_id) | ||
| deleted += 1 | ||
| except Exception: | ||
| pass | ||
|
|
||
| print(f"Deleted {deleted} memories for user_id={user_id}, group={group}") | ||
|
|
||
| client.close() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| import os | ||
| import uuid | ||
| from engram import EngramClient, APIError | ||
|
|
||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
|
|
||
| test_user_id = f"test-{uuid.uuid4().hex[:8]}" | ||
|
|
||
| # Setup: store a memory so we can get and delete it | ||
| run = client.memories.add( | ||
| "The user prefers dark mode", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
| status = client.runs.wait(run.run_id) | ||
| assert status.status == "completed" | ||
| assert status.committed_operations is not None | ||
| assert len(status.memories_created) >= 1 | ||
|
|
||
| memory_id = status.memories_created[0].memory_id | ||
|
|
||
| # START GetMemory | ||
| memory = client.memories.get( | ||
| memory_id, | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
|
|
||
| print(memory.content) | ||
| print(memory.topic) | ||
| # END GetMemory | ||
|
|
||
| assert memory.id == memory_id | ||
| assert "dark mode" in memory.content | ||
|
|
||
| # START DeleteMemory | ||
| client.memories.delete( | ||
| memory_id, | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
| # END DeleteMemory | ||
|
|
||
| # Verify the memory was deleted | ||
| try: | ||
| client.memories.get(memory_id, user_id=test_user_id, group="default") | ||
| assert False, "Expected memory to be deleted" | ||
| except APIError: | ||
| pass # Memory no longer exists | ||
|
|
||
| # Cleanup | ||
| _all = client.memories.search(query="dark mode", user_id=test_user_id, group="default") | ||
| for _m in _all: | ||
| client.memories.delete(_m.id, user_id=test_user_id, group="default") | ||
|
|
||
| client.close() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import os | ||
| import time | ||
| import uuid | ||
| from engram import EngramClient | ||
|
|
||
| # START Connect | ||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
| # END Connect | ||
|
|
||
| test_user_id = f"test-{uuid.uuid4().hex[:8]}" | ||
|
|
||
| # START AddMemory | ||
| run = client.memories.add( | ||
| "The user prefers dark mode and uses VS Code as their primary editor.", | ||
| user_id=test_user_id, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we can put some static string to show that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm using this because I ran into problems with deduplication with the same user id when running the tests multiple times, I will see if I can remove it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gotcha. My point is, use some "readable" string instead of uuid, so users don't think we require uuid here. |
||
| group="default", | ||
|
g-despot marked this conversation as resolved.
Outdated
|
||
| ) | ||
|
|
||
| print(run.run_id) | ||
| print(run.status) | ||
| # END AddMemory | ||
|
|
||
| assert run.run_id is not None | ||
|
|
||
| # START CheckRun | ||
| status = client.runs.wait(run.run_id) | ||
|
|
||
| print(status.status) | ||
| # END CheckRun | ||
|
|
||
| assert status.status == "completed" | ||
| assert status.committed_operations is not None | ||
| assert len(status.memories_created) >= 1 | ||
|
|
||
| time.sleep(3) | ||
|
|
||
| # START SearchMemory | ||
| results = client.memories.search( | ||
| query="What editor does the user prefer?", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
|
|
||
| for memory in results: | ||
| print(memory.content) | ||
| # END SearchMemory | ||
|
|
||
| assert len(results) >= 1 | ||
| assert any("VS Code" in m.content or "editor" in m.content or "dark mode" in m.content for m in results) | ||
|
|
||
| # Cleanup | ||
| for _m in results: | ||
| try: | ||
| client.memories.delete(_m.id, user_id=test_user_id, group="default") | ||
| except Exception: | ||
| pass | ||
|
|
||
| client.close() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import os | ||
| import uuid | ||
| from engram import EngramClient, RetrievalConfig | ||
|
|
||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
|
|
||
| test_user_id = f"test-{uuid.uuid4().hex[:8]}" | ||
|
|
||
| # Setup: store a memory so we have data to search | ||
| run = client.memories.add( | ||
| "The user prefers dark mode and works primarily in Python. They are building a RAG application.", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
| status = client.runs.wait(run.run_id) | ||
| assert status.status == "completed" | ||
| assert len(status.memories_created) >= 1 | ||
|
|
||
| # START BasicSearch | ||
| results = client.memories.search( | ||
| query="What programming language does the user prefer?", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| retrieval_config=RetrievalConfig(retrieval_type="hybrid", limit=5), | ||
| ) | ||
|
|
||
| for memory in results: | ||
| print(memory.content) | ||
| # END BasicSearch | ||
|
|
||
| assert len(results) >= 1 | ||
|
|
||
| # START VectorSearch | ||
| results = client.memories.search( | ||
| query="What programming language does the user prefer?", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| retrieval_config=RetrievalConfig(retrieval_type="vector", limit=10), | ||
| ) | ||
| # END VectorSearch | ||
|
|
||
| assert len(results) >= 1 | ||
|
|
||
| # START BM25Search | ||
| results = client.memories.search( | ||
| query="What programming language does the user prefer?", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| retrieval_config=RetrievalConfig(retrieval_type="bm25", limit=10), | ||
| ) | ||
| # END BM25Search | ||
|
|
||
| assert len(results) >= 1 | ||
|
|
||
| # START HybridSearch | ||
| results = client.memories.search( | ||
| query="What programming language does the user prefer?", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| retrieval_config=RetrievalConfig(retrieval_type="hybrid", limit=10), | ||
| ) | ||
| # END HybridSearch | ||
|
|
||
| assert len(results) >= 1 | ||
|
|
||
| # Discover actual topic name from existing results | ||
| topic = results[0].topic | ||
|
|
||
| # START TopicFilter | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had trouble grokking this concept that searching with a I think one way to make this more clear could be to explicitly say "UserKnowledge" here instead of the generic |
||
| results = client.memories.search( | ||
| query="user preferences", | ||
| topics=[topic], | ||
| user_id=test_user_id, | ||
| group="default", | ||
| retrieval_config=RetrievalConfig(retrieval_type="hybrid", limit=10), | ||
| ) | ||
|
|
||
| for memory in results: | ||
| print(memory.content) | ||
| # END TopicFilter | ||
|
|
||
| assert len(results) >= 1 | ||
| assert all(m.topic == topic for m in results) | ||
|
|
||
| # Cleanup | ||
| _all = client.memories.search(query="user", user_id=test_user_id, group="default") | ||
| for _m in _all: | ||
| client.memories.delete(_m.id, user_id=test_user_id, group="default") | ||
|
|
||
| client.close() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import os | ||
| import time | ||
| import uuid | ||
| from engram import EngramClient, PreExtractedContent | ||
|
|
||
| client = EngramClient( | ||
| api_key=os.environ["ENGRAM_API_KEY"], base_url="https://api.engram.weaviate.io" | ||
| ) | ||
|
|
||
| test_user_id = f"test-{uuid.uuid4().hex[:8]}" | ||
|
|
||
| # START StoreString | ||
| run = client.memories.add( | ||
| "The user prefers dark mode and works primarily in Python. They are building a RAG application.", | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
|
|
||
| print(run.run_id) | ||
| print(run.status) | ||
| # END StoreString | ||
|
|
||
| assert run.run_id is not None | ||
| status = client.runs.wait(run.run_id) | ||
| assert status.status == "completed" | ||
| assert len(status.memories_created) >= 1 | ||
|
|
||
| time.sleep(3) | ||
|
|
||
| results = client.memories.search(query="Python RAG dark mode", user_id=test_user_id, group="default") | ||
| assert len(results) >= 1 | ||
| assert any("Python" in m.content or "dark mode" in m.content or "RAG" in m.content for m in results) | ||
|
|
||
| # START StorePreExtracted | ||
| run = client.memories.add( | ||
| PreExtractedContent( | ||
| content="User prefers dark mode", | ||
| ), | ||
| user_id=test_user_id, | ||
| group="default", | ||
| ) | ||
|
|
||
| print(run.run_id) | ||
| print(run.status) | ||
| # END StorePreExtracted | ||
|
|
||
| assert run.run_id is not None | ||
| status = client.runs.wait(run.run_id) | ||
| assert status.status == "completed" | ||
|
|
||
| results = client.memories.search(query="dark mode preference", user_id=test_user_id, group="default") | ||
| assert len(results) >= 1 | ||
| assert any("dark mode" in m.content for m in results) | ||
|
|
||
| # START StoreConversation | ||
| run = client.memories.add( | ||
| [ | ||
| {"role": "user", "content": "I just moved to Berlin and I am looking for a good coffee shop."}, | ||
| {"role": "assistant", "content": "Welcome to Berlin! Here are some popular coffee shops in the city..."}, | ||
| {"role": "user", "content": "I prefer specialty coffee, not chains."}, | ||
| ], | ||
| user_id=test_user_id, | ||
| conversation_id=str(uuid.uuid4()), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know the best way to make it clear in the docs, but we want to separate the idea that adding conversation content type data means you need a conversation ID. They're separate concepts, so you can add conversation data (list of role/content) without a Whether the |
||
| group="default", | ||
| ) | ||
|
|
||
| print(run.run_id) | ||
| print(run.status) | ||
| # END StoreConversation | ||
|
|
||
| assert run.run_id is not None | ||
| status = client.runs.wait(run.run_id) | ||
| assert status.status == "completed" | ||
|
|
||
| results = client.memories.search(query="Berlin coffee specialty", user_id=test_user_id, group="default") | ||
| assert len(results) >= 1 | ||
| assert any("Berlin" in m.content or "coffee" in m.content for m in results) | ||
|
|
||
| # Cleanup | ||
| _all = client.memories.search(query="user", user_id=test_user_id, group="default") | ||
| for _m in _all: | ||
| client.memories.delete(_m.id, user_id=test_user_id, group="default") | ||
|
|
||
| client.close() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't pass
base_url. that's the whole idea of SDK to encapsulate things like this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will remove this completely