fix: encode dynamic URL path segments (#5963)

Co-authored-by: kartik-mem0 <kartik.labhshetwar@mem0.ai>
This commit is contained in:
VectorPeak
2026-07-07 16:11:54 +05:30
committed by GitHub
co-authored by kartik-mem0
parent 87276ef968
commit cc52f0e367
9 changed files with 374 additions and 39 deletions
+32 -12
View File
@@ -3,6 +3,7 @@ import logging
import os
import warnings
from typing import Any, Dict, List, Optional
from urllib.parse import quote
import httpx
import requests
@@ -42,6 +43,10 @@ def _validate_and_trim_search_query(query: str) -> str:
return trimmed
def _encode_path_segment(value: Any) -> str:
return quote(str(value), safe="")
def _maybe_alias_anon_to_email(user_email):
"""Fire $identify per prior anon ID so PostHog merges them into email.
@@ -229,7 +234,7 @@ class MemoryClient:
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
"""
params = self._prepare_params()
response = self.client.get(f"/v1/memories/{memory_id}/", params=params)
response = self.client.get(f"/v1/memories/{_encode_path_segment(memory_id)}/", params=params)
response.raise_for_status()
capture_client_event("client.get", self, {"memory_id": memory_id, "sync_type": "sync"})
return response.json()
@@ -367,7 +372,7 @@ class MemoryClient:
capture_client_event("client.update", self, {"memory_id": memory_id, "sync_type": "sync"})
params = self._prepare_params()
response = self.client.put(f"/v1/memories/{memory_id}/", json=payload, params=params)
response = self.client.put(f"/v1/memories/{_encode_path_segment(memory_id)}/", json=payload, params=params)
response.raise_for_status()
return response.json()
@@ -395,7 +400,7 @@ class MemoryClient:
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
"""
params = self._prepare_params({"delete_linked": delete_linked or None})
response = self.client.delete(f"/v1/memories/{memory_id}/", params=params)
response = self.client.delete(f"/v1/memories/{_encode_path_segment(memory_id)}/", params=params)
response.raise_for_status()
capture_client_event(
"client.delete", self, {"memory_id": memory_id, "delete_linked": delete_linked, "sync_type": "sync"}
@@ -452,7 +457,7 @@ class MemoryClient:
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
"""
params = self._prepare_params()
response = self.client.get(f"/v1/memories/{memory_id}/history/", params=params)
response = self.client.get(f"/v1/memories/{_encode_path_segment(memory_id)}/history/", params=params)
response.raise_for_status()
capture_client_event("client.history", self, {"memory_id": memory_id, "sync_type": "sync"})
return response.json()
@@ -513,7 +518,10 @@ class MemoryClient:
# Delete entities and check response immediately
for entity in to_delete:
response = self.client.delete(f"/v2/entities/{entity['type']}/{entity['name']}/", params=params)
response = self.client.delete(
f"/v2/entities/{_encode_path_segment(entity['type'])}/{_encode_path_segment(entity['name'])}/",
params=params,
)
response.raise_for_status()
capture_client_event(
@@ -691,7 +699,9 @@ class MemoryClient:
ValueError: If org_id or project_id are not set.
"""
logger.warning(
"get_project() method is going to be deprecated in version v1.0 of the package. Please use the client.project.get() method instead."
"get_project() method is going to be deprecated in version v1.0 "
"of the package. Please use the client.project.get() method "
"instead."
)
if not (self.org_id and self.project_id):
raise ValueError("org_id and project_id must be set to access instructions or categories")
@@ -1147,7 +1157,7 @@ class AsyncMemoryClient:
@api_error_handler
async def get(self, memory_id: str) -> Dict[str, Any]:
params = self._prepare_params()
response = await self.async_client.get(f"/v1/memories/{memory_id}/", params=params)
response = await self.async_client.get(f"/v1/memories/{_encode_path_segment(memory_id)}/", params=params)
response.raise_for_status()
capture_client_event("client.get", self, {"memory_id": memory_id, "sync_type": "async"})
return response.json()
@@ -1285,7 +1295,9 @@ class AsyncMemoryClient:
capture_client_event("client.update", self, {"memory_id": memory_id, "sync_type": "async"})
params = self._prepare_params()
response = await self.async_client.put(f"/v1/memories/{memory_id}/", json=payload, params=params)
response = await self.async_client.put(
f"/v1/memories/{_encode_path_segment(memory_id)}/", json=payload, params=params
)
response.raise_for_status()
return response.json()
@@ -1313,7 +1325,7 @@ class AsyncMemoryClient:
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
"""
params = self._prepare_params({"delete_linked": delete_linked or None})
response = await self.async_client.delete(f"/v1/memories/{memory_id}/", params=params)
response = await self.async_client.delete(f"/v1/memories/{_encode_path_segment(memory_id)}/", params=params)
response.raise_for_status()
capture_client_event(
"client.delete", self, {"memory_id": memory_id, "delete_linked": delete_linked, "sync_type": "async"}
@@ -1365,7 +1377,10 @@ class AsyncMemoryClient:
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
"""
params = self._prepare_params()
response = await self.async_client.get(f"/v1/memories/{memory_id}/history/", params=params)
response = await self.async_client.get(
f"/v1/memories/{_encode_path_segment(memory_id)}/history/",
params=params,
)
response.raise_for_status()
capture_client_event("client.history", self, {"memory_id": memory_id, "sync_type": "async"})
return response.json()
@@ -1426,7 +1441,10 @@ class AsyncMemoryClient:
# Delete entities and check response immediately
for entity in to_delete:
response = await self.async_client.delete(f"/v2/entities/{entity['type']}/{entity['name']}/", params=params)
response = await self.async_client.delete(
f"/v2/entities/{_encode_path_segment(entity['type'])}/{_encode_path_segment(entity['name'])}/",
params=params,
)
response.raise_for_status()
capture_client_event(
@@ -1590,7 +1608,9 @@ class AsyncMemoryClient:
ValueError: If org_id or project_id are not set.
"""
logger.warning(
"get_project() method is going to be deprecated in version v1.0 of the package. Please use the client.project.get() method instead."
"get_project() method is going to be deprecated in version v1.0 "
"of the package. Please use the client.project.get() method "
"instead."
)
if not (self.org_id and self.project_id):
raise ValueError("org_id and project_id must be set to access instructions or categories")