Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/engram/_includes/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions docs/engram/_includes/check_run_status.py
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()
25 changes: 25 additions & 0 deletions docs/engram/_includes/cleanup_memories.py
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()
Binary file added docs/engram/_includes/concepts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions docs/engram/_includes/manage_memories.py
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()
60 changes: 60 additions & 0 deletions docs/engram/_includes/quickstart.py
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"
Copy link
Copy Markdown

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.

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.

Good point, will remove this completely

)
# 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,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

maybe we can put some static string to show that user_id can be simple user name? Field is called user_id for only reason to emphasize that it has to be unique.

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.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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",
Comment thread
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()
92 changes: 92 additions & 0 deletions docs/engram/_includes/search_memories.py
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I had trouble grokking this concept that searching with a Group means retrieving memories within all the Topics associated with that Group.

I think one way to make this more clear could be to explicitly say "UserKnowledge" here instead of the generic topic variable.

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()
84 changes: 84 additions & 0 deletions docs/engram/_includes/store_memories.py
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()),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The 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 conversation_id, and conversely could include a conversation_id for string / pre-extracted content types.

Whether the conversation_id is required when adding or not just depends on the topic in that group, not the content type. I'd worry that only including that kwarg when adding conversation data in these examples conflates those two.

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()
Loading
Loading