Vity Python SDK
Long-term memory for AI applications, by Maximem AI.
Store facts and preferences, capture conversations, and recall the right context for every prompt,
with a small, typed client for both synchronous and asyncio code.
from maximem_vity import VityClient
client = VityClient(channel="my-app") # reads MAXIMEM_API_KEY
client.store("User prefers dark mode", memory_type="preference")
print(client.recall("What theme does the user like?"))
Using JavaScript or TypeScript? Install @maximem/vity-sdk from npm.
Contents
- Installation
- Quick start
- Concepts
- Configuration
- API reference
- LLM tool calling
- Error handling
- Retries and timeouts
- Testing
- Upgrading from 0.2.x
- License
Installation
pip install maximem-vity-sdk
Requires Python 3.9 or later. The package is fully typed.
Quick start
Create an API key at app.maximem.ai/api-keys and export it:
export MAXIMEM_API_KEY="mx_..."
A typical agent turn recalls memory before answering and captures the exchange afterwards:
from maximem_vity import VityClient
with VityClient(channel="support-bot") as client:
# Before answering: fetch relevant memory for the system prompt.
context = client.recall("Can you book my usual table?")
# After answering: capture the exchange so Vity can learn from it.
client.capture(
[
{"role": "user", "content": "Can you book my usual table?"},
{"role": "assistant", "content": "Booked the window table for 7pm."},
],
session_key="conversation-8f2c",
)
# Store an explicit fact.
client.store("Prefers window seats", memory_type="preference", importance="high")
# Search memory directly.
for hit in client.search("seating preferences", top_k=5):
print(f"{hit['score']:.2f} {hit['content']}")
Async
AsyncVityClient takes the same arguments and exposes the same methods as coroutines:
import asyncio
from maximem_vity import AsyncVityClient
async def main() -> None:
async with AsyncVityClient(channel="support-bot") as client:
context = await client.recall("What does the user like to eat?")
asyncio.run(main())
Concepts
Memory belongs to your account. All API keys on a Maximem account share the same memory. Rotating or adding keys never loses anything.
Channels and sessions. Set channel to the name of your integration ("slack", "support-bot").
Pass a session_key to capture() that stays the same for every turn of one conversation and
changes for each new conversation.
store() or capture()?
store() |
capture() |
|
|---|---|---|
| Input | One explicit fact | A conversation (up to 50 messages) |
| Saved | Immediately | In the background, usually within seconds to minutes |
| What is kept | Exactly what you send | Durable facts only; small talk is ignored |
A successful capture() means the conversation was accepted for processing.
recall() or search()? recall() returns a text block ready to drop into a prompt.
search() returns scored memory records for your own logic.
Configuration
| Argument | Environment variable | Default | Description |
|---|---|---|---|
api_key |
MAXIMEM_API_KEY |
required | Your Maximem API key. |
endpoint |
MAXIMEM_ENDPOINT |
Maximem API | Only needed for a non-default environment. |
channel |
"unspecified" |
The name of your integration. Recommended. | |
agent_id |
"unspecified" |
Tag recorded on stored memories. | |
timeout |
30.0 |
Request timeout in seconds. | |
max_retries |
2 |
Retries for temporary failures. 0 disables them. |
|
http_client |
managed | Your own httpx.Client / httpx.AsyncClient (proxies, custom TLS, tests). |
Arguments take precedence over environment variables.
API reference
Every method is available on VityClient and, as a coroutine, on AsyncVityClient.
Memory
| Method | Returns |
|---|---|
recall(current_prompt, recent_messages=None, max_tokens=1000, strategy="hybrid") |
str: prompt-ready context, or "" |
capture(messages, session_key="", agent_id="", channel=None) |
CaptureResult |
store(content, memory_type="fact", category="", importance="medium") |
StoreResult: {"id", "stored"} |
search(query, top_k=10, category="", min_score=0.0) |
list[SearchResult]: content, type, score, id, created_at |
forget(query="", dry_run=True, delete_all=False) |
ForgetResult: {"count", "ids"} |
capture_status(request_id) |
dict |
strategy:"semantic","recency"or"hybrid".memory_type:fact,preference,emotion,episode,knowledgeorprofile. Usecategory(preference,fact,task,relationship,context) to set the category directly.importance:"low","medium"or"high".
Deleting memories
forget() only previews unless you pass dry_run=False. Deleting without a query removes
all memories on the account, so it also requires delete_all=True:
client.forget("old employer") # preview what would be deleted
client.forget("old employer", dry_run=False) # delete matching memories
client.forget(dry_run=False, delete_all=True) # delete everything
Knowledge
| Method | Returns |
|---|---|
knowledge(query="", limit=10, offset=0, min_score=0.3, filters=None, include=None, ...) |
KnowledgeResult |
knowledge_diff(input_text, purpose, ...) |
KnowledgeDiffResult |
knowledge() returns consolidated knowledge about the user (topics, summaries, confidence), with
pagination through limit and offset. Filter with keys such as topic_category,
confidence_min, seen_after and seen_before; choose sections with include
("items", "facets", "profile").
knowledge_diff() returns the knowledge most relevant to a piece of text. purpose describes what
you are looking for and why:
client.knowledge_diff(
input_text="Draft: proposal to move our analytics to ClickHouse",
purpose="the user's earlier decisions and opinions about analytics databases",
)
Meetings
| Method | Returns |
|---|---|
meetings_enabled() |
bool: False if unavailable |
meeting_ask(question, max_memories=12, meeting_type="", status="", seed_person_id="") |
dict |
get_meeting(external_id) |
dict |
list_meeting_reviews() |
list[dict] |
LLM tool calling
as_tool() lets a model search and save memories itself. It provides two tools,
search_memory and save_memory, in OpenAI or Anthropic format:
from openai import OpenAI
from maximem_vity import VityClient
llm, vity = OpenAI(), VityClient(channel="assistant")
memory = vity.as_tool(style="openai") # or style="anthropic"
messages = [{"role": "user", "content": "What am I allergic to?"}]
response = llm.chat.completions.create(model="gpt-4o", messages=messages, tools=memory.definitions)
for call in response.choices[0].message.tool_calls or []:
if memory.handles(call.function.name):
result = memory.call(call.function.name, call.function.arguments)
messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
definitionsis plain JSON and can be passed directly astools.call()accepts arguments as a JSON string or a dict, and returns a JSON string.- If the model sends invalid arguments,
call()returns{"error": ...}so the model can retry. Other problems, such as an invalid API key, raise an exception. - Pass
read_only=Trueto offer onlysearch_memory. - The model chooses the query or the fact to save. It cannot change whose memory is used.
With AsyncVityClient, use await memory.call(...).
Error handling
All exceptions inherit from VityError:
| Exception | Raised when |
|---|---|
VityInvalidInputError |
An argument is invalid. Usually raised before any request is sent. |
VityAuthError |
The API key is missing, invalid or revoked. |
VityInsufficientCreditsError |
The account has run out of credits. |
VityNotFoundError |
The requested item does not exist. |
VityRateLimitError |
Too many requests. Check retry_after. |
VityUnavailableError |
A temporary service or network problem, or a timeout. |
Each exception has message, status_code, code, request_id, retry_after and retryable.
Include request_id when contacting support.
import time
from maximem_vity import VityError, VityInsufficientCreditsError, VityRateLimitError
try:
client.store("User is vegetarian", memory_type="preference")
except VityInsufficientCreditsError:
... # prompt the account owner to add credits
except VityRateLimitError as err:
time.sleep(err.retry_after or 60)
except VityError as err:
print(f"Vity request failed: {err} (request id: {err.request_id})")
Retries and timeouts
The client retries temporary failures automatically, up to max_retries times with exponential
backoff:
- Read operations (
recall,search,knowledge, ...) are retried after temporary errors. - Write operations (
store,capture,forget) are retried only when the request never reached the service. This prevents a memory from being saved twice. - The client never waits more than a few seconds before retrying. If the service asks for a longer
wait, you get a
VityRateLimitErrorwithretry_afterset and can decide what to do.
Input is validated before sending. For example, capture() accepts up to 50 messages per call and
store() up to 10,000 characters, so mistakes fail fast with a clear message.
Logs go to the maximem_vity logger: retries at WARNING, requests at DEBUG. The API key is
never logged.
Testing
Use an httpx.MockTransport to test your code without network access:
import httpx
from maximem_vity import VityClient
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(200, json={"context": "User prefers dark mode", "sources": []})
client = VityClient(api_key="mx_test", http_client=httpx.Client(transport=httpx.MockTransport(handler)))
assert client.recall("theme?") == "User prefers dark mode"
Upgrading from 0.2.x
0.3.0 is backwards compatible for typical use. Check these changes:
user_idis deprecated. It is ignored because memory belongs to the account that owns the key. It will be removed in 0.4.0.channelandagent_iddefault to"unspecified". Setchannelto your integration's name.- Deleting everything requires confirmation:
forget(dry_run=False, delete_all=True). search(min_score=0.0)now means no minimum score, so you may see more results.- Invalid arguments raise
VityInvalidInputErrorbefore any request is sent. - New exceptions
VityInvalidInputError,VityInsufficientCreditsErrorandVityNotFoundErrorinherit fromVityError, so existingexcept VityErrorblocks keep working.
License
MIT
Metadata
Release files for maximem-vity-sdk 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| maximem_vity_sdk-0.3.0.tar.gz | 37.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| maximem_vity_sdk-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 66.5 kB
Release files / maximem_vity_sdk-0.3.0.tar.gz
| Download URL | maximem_vity_sdk-0.3.0.tar.gz |
|---|---|
| Size | 37.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15af0e1c9ba89ab7ad48dc0d5995c8b821fda67343999d9576724286e0ac989b
|
|
BLAKE2b-256 checksum How to use checksums |
549a3dadd07feae837ef7d476628239db590bed13f24c3cfbb5b42fd8e14d3b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.1
|
Release files / maximem_vity_sdk-0.3.0-py3-none-any.whl
| Download URL | maximem_vity_sdk-0.3.0-py3-none-any.whl |
|---|---|
| Size | 28.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bad3a3ac20b385093e2409dbdc6201e193faecbd500a5f7a9a6f9ced2592729f
|
|
BLAKE2b-256 checksum How to use checksums |
13094be984abf5506d30b8ae56b300d8c459baef200208c8a57dfdb28ef25118
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.1
|