rest_api_learnings.py
"""Using the learnings REST API endpoints directly.
This example demonstrates:
- Creating a learning record via POST /learnings
- Listing learnings via GET /learnings
- Listing the users that own learnings via GET /learnings/users
- Fetching a single learning via GET /learnings/{id}
- Updating content/metadata via PATCH /learnings/{id}
- Deleting via DELETE /learnings/{id}
- Deleting a user and all their learnings via DELETE /learnings/users/{user_id}
Requires: a running AgentOS server. Start one with:
.venvs/demo/bin/python cookbook/05_agent_os/learnings/learnings_with_agentos.py
Then in another terminal:
.venvs/demo/bin/python cookbook/05_agent_os/learnings/rest_api_learnings.py
"""
import httpx
BASE_URL = "http://127.0.0.1:7777"
client = httpx.Client(base_url=BASE_URL, timeout=30)
def main():
# =========================================================================
# 1. Create a learning record
# =========================================================================
# For the identity-keyed types (user_profile, user_memory, session_context,
# entity_memory) the record id is derived deterministically from the identity fields,
# so it reconciles with what the agent reads/writes. Include those identity fields in
# `content` too (e.g. user_id) so the agent can deserialize the record. Re-POSTing the
# same identity returns 409 -- use PATCH to update.
print("=== Create Learning ===\n")
resp = client.post(
"/learnings",
json={
"learning_type": "user_profile",
"namespace": "global",
"user_id": "demo-user",
"content": {
"user_id": "demo-user",
"name": "Yash",
"preferences": {"language": "Python", "tone": "concise"},
},
"metadata": {"source": "rest-api-demo"},
},
)
resp.raise_for_status()
learning = resp.json()
learning_id = learning["learning_id"]
print(f"Created: {learning_id}")
print(f" Type: {learning['learning_type']}")
print(f" Content: {learning['content']}")
# =========================================================================
# 2. List learnings (with filters)
# =========================================================================
print("\n=== List Learnings ===\n")
resp = client.get(
"/learnings", params={"user_id": "demo-user", "limit": 10, "page": 1}
)
resp.raise_for_status()
result = resp.json()
records = result["data"]
meta = result["meta"]
print(
"Page {} of {} (total: {})\n".format(
meta["page"], meta["total_pages"], meta["total_count"]
)
)
for r in records:
print(f" {r['learning_id']} -> {r['learning_type']} (user={r['user_id']})")
# =========================================================================
# 3. List the users that own learnings
# =========================================================================
# Entry point for a per-user view: list users first, then drill into a
# single user's learnings via GET /learnings?user_id=...
print("\n=== List Learning Users ===\n")
resp = client.get("/learnings/users", params={"learning_type": "user_profile"})
resp.raise_for_status()
for u in resp.json()["data"]:
print(
" user={} last_updated={}".format(
u["user_id"], u["last_learning_updated_at"]
)
)
# =========================================================================
# 4. Fetch a single learning
# =========================================================================
print("\n=== Get Learning ===\n")
resp = client.get(f"/learnings/{learning_id}")
resp.raise_for_status()
detail = resp.json()
print(f" ID: {detail['learning_id']}")
print(f" Namespace: {detail['namespace']}")
print(f" Content keys: {list((detail.get('content') or {}).keys())}")
# =========================================================================
# 5. Update content + metadata (full replace)
# =========================================================================
print("\n=== Update Learning ===\n")
resp = client.patch(
f"/learnings/{learning_id}",
json={
"content": {
"name": "Yash",
"preferences": {
"language": "Python",
"tone": "concise",
"loves": "agentic frameworks",
},
},
"metadata": {"source": "rest-api-demo", "version": 2},
},
)
resp.raise_for_status()
updated = resp.json()
print(f" Updated content: {updated['content']}")
print(f" Updated metadata: {updated['metadata']}")
# =========================================================================
# 6. Delete the learning
# =========================================================================
print("\n=== Delete Learning ===\n")
resp = client.delete(f"/learnings/{learning_id}")
resp.raise_for_status()
print(f" Deleted (status {resp.status_code})")
# Verify it's gone
resp = client.get(f"/learnings/{learning_id}")
print(f" Follow-up GET status: {resp.status_code} (expect 404)")
# =========================================================================
# 7. Delete a user and all of their learnings
# =========================================================================
# Seed a couple of records for a throwaway user, then remove the user and
# everything associated with them in one call. decision_log uses a generated id
# (not identity-keyed), so a user can have many of them.
print("\n=== Delete Learning User ===\n")
for note in ("first", "second"):
client.post(
"/learnings",
json={
"learning_type": "decision_log",
"user_id": "bulk-demo-user",
"content": {"note": note},
},
).raise_for_status()
resp = client.delete("/learnings/users/bulk-demo-user")
resp.raise_for_status()
print(f" Deleted user (status {resp.status_code})")
# Verify the user no longer has any records
resp = client.get("/learnings", params={"user_id": "bulk-demo-user"})
resp.raise_for_status()
print(
f" Remaining records for user: {resp.json()['meta']['total_count']} (expect 0)"
)
print("\nDone.")
if __name__ == "__main__":
main()
Run the Example
Set up your virtual environment
uv venv --python 3.12
source .venv/bin/activate
uv venv --python 3.12
.venv\Scripts\activate