memorysync 1.5.0__tar.gz → 1.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,18 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: memorysync
3
- Version: 1.5.0
3
+ Version: 1.7.0
4
4
  Summary: Official Python client for the MemorySync API.
5
5
  Project-URL: Homepage, https://memorysync.io
6
6
  Project-URL: Documentation, https://docs.memorysync.io
7
+ Project-URL: API Reference, https://docs.memorysync.io/api/overview
8
+ Project-URL: Quickstart, https://docs.memorysync.io/sdks/python/overview
9
+ Project-URL: Changelog, https://docs.memorysync.io/release-notes
10
+ Project-URL: Support, https://docs.memorysync.io/debugging/support
11
+ Project-URL: Status, https://status.memorysync.io
7
12
  Author: MemorySync
8
13
  License: MIT
9
14
  License-File: LICENSE
10
- Keywords: client,memory,memorysync,sdk
15
+ Keywords: agent-memory,ai,ai-agents,client,context,llm,long-term-memory,memory,memorysync,rag,retrieval,sdk
11
16
  Classifier: Development Status :: 5 - Production/Stable
12
17
  Classifier: Intended Audience :: Developers
13
18
  Classifier: License :: OSI Approved :: MIT License
@@ -4,13 +4,26 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memorysync"
7
- version = "1.5.0"
7
+ version = "1.7.0"
8
8
  description = "Official Python client for the MemorySync API."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
11
11
  requires-python = ">=3.9"
12
12
  authors = [{ name = "MemorySync" }]
13
- keywords = ["memorysync", "memory", "sdk", "client"]
13
+ keywords = [
14
+ "memorysync",
15
+ "memory",
16
+ "sdk",
17
+ "client",
18
+ "ai",
19
+ "llm",
20
+ "agent-memory",
21
+ "long-term-memory",
22
+ "context",
23
+ "retrieval",
24
+ "rag",
25
+ "ai-agents",
26
+ ]
14
27
  classifiers = [
15
28
  "Development Status :: 5 - Production/Stable",
16
29
  "Intended Audience :: Developers",
@@ -31,6 +44,11 @@ dependencies = [
31
44
  [project.urls]
32
45
  Homepage = "https://memorysync.io"
33
46
  Documentation = "https://docs.memorysync.io"
47
+ "API Reference" = "https://docs.memorysync.io/api/overview"
48
+ Quickstart = "https://docs.memorysync.io/sdks/python/overview"
49
+ Changelog = "https://docs.memorysync.io/release-notes"
50
+ Support = "https://docs.memorysync.io/debugging/support"
51
+ Status = "https://status.memorysync.io"
34
52
 
35
53
  [tool.hatch.build.targets.wheel]
36
54
  packages = ["src/memorysync"]
@@ -53,10 +53,15 @@ from .control_plane_types import (
53
53
  ExportJobListResponse,
54
54
  Integration,
55
55
  JsonObject,
56
+ CurrentUserResponse,
56
57
  LoginRequest,
57
58
  LoginResponse,
58
59
  LoginSession,
59
60
  LoginTokens,
61
+ RefreshRequest,
62
+ SignupRequest,
63
+ SignupResponse,
64
+ TokenPair,
60
65
  OrganizationMembership,
61
66
  Project,
62
67
  RenameProjectRequest,
@@ -114,8 +119,9 @@ __all__ = [
114
119
  __all__ += [
115
120
  "ControlPlaneClient", "AsyncControlPlaneClient", "JsonObject",
116
121
  "BulkRevokeRequest", "BulkRevokeResult", "BulkRevokeResponse",
117
- "ApiKeyTestResponse", "LoginRequest", "LoginTokens", "LoginSession",
118
- "LoginResponse", "CurrentPlanResponse", "Session", "SessionsResponse",
122
+ "ApiKeyTestResponse", "SignupRequest", "SignupResponse", "LoginRequest",
123
+ "LoginTokens", "LoginSession", "LoginResponse", "RefreshRequest",
124
+ "TokenPair", "CurrentUserResponse", "CurrentPlanResponse", "Session", "SessionsResponse",
119
125
  "Integration", "CreateOrganizationRequest", "OrganizationMembership",
120
126
  "Project", "CreateProjectRequest",
121
127
  "RenameProjectRequest", "CreateWebhookRequest", "CreatedWebhook",
@@ -0,0 +1 @@
1
+ __version__ = "1.7.0"
@@ -14,10 +14,10 @@ from ._version import __version__
14
14
  from .control_plane_types import (
15
15
  ApiKeyTestResponse, BulkRevokeResponse, CreatedWebhook, CreateExportResponse,
16
16
  CurrentPlanResponse, ExportDownloadUrl, ExportJob, ExportJobListResponse,
17
- Integration, LoginResponse, OrganizationMembership, Project, Session,
18
- SessionsResponse, Webhook, WebhookDeliveriesResponse, WebhookDelivery,
19
- WebhookEventTypesResponse, WebhookHealth, WebhookReplayResponse,
20
- WebhooksResponse, WebhookTestResponse,
17
+ CurrentUserResponse, Integration, LoginResponse, OrganizationMembership,
18
+ Project, Session, SessionsResponse, SignupResponse, TokenPair, Webhook,
19
+ WebhookDeliveriesResponse, WebhookDelivery, WebhookEventTypesResponse,
20
+ WebhookHealth, WebhookReplayResponse, WebhooksResponse, WebhookTestResponse,
21
21
  )
22
22
  from .errors import (
23
23
  AuthError, MemorySyncError, NotFoundError, RateLimitError, ServerError,
@@ -41,6 +41,23 @@ def _required_text(value: str, name: str) -> str:
41
41
  return value
42
42
 
43
43
 
44
+ def _email(value: str) -> str:
45
+ _required_text(value, "email")
46
+ if "@" not in value or value.startswith("@") or value.endswith("@"):
47
+ raise ValidationError("email must be a valid email address")
48
+ return value
49
+
50
+
51
+ def _signup_fields(email: str, password: str, organization_name: str) -> None:
52
+ _email(email)
53
+ _required_text(password, "password")
54
+ if len(password) < 8:
55
+ raise ValidationError("password must contain at least 8 characters")
56
+ _required_text(organization_name, "organization_name")
57
+ if not 2 <= len(organization_name.strip()) <= 100:
58
+ raise ValidationError("organization_name must contain between 2 and 100 characters")
59
+
60
+
44
61
  def _bounded(value: int, name: str, minimum: int, maximum: int) -> int:
45
62
  if not isinstance(value, int) or isinstance(value, bool) or not minimum <= value <= maximum:
46
63
  raise ValidationError(f"{name} must be an integer between {minimum} and {maximum}")
@@ -340,13 +357,44 @@ class ControlPlaneClient(_ControlPlaneBase):
340
357
  raw = self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=_project_override(project_id))
341
358
  return cast(ApiKeyTestResponse, raw)
342
359
 
360
+ def signup(
361
+ self, email: str, password: str, organization_name: str, *,
362
+ full_name: Optional[str] = None,
363
+ ) -> SignupResponse:
364
+ _signup_fields(email, password, organization_name)
365
+ raw = self._request(
366
+ "POST", "/auth/signup",
367
+ json=_body(email=email, password=password, organization_name=organization_name, full_name=full_name),
368
+ require_auth=False, project_id=None,
369
+ )
370
+ return cast(SignupResponse, raw)
371
+
343
372
  def login(self, email: str, password: str) -> LoginResponse:
344
- _required_text(email, "email")
345
- if "@" not in email:
346
- raise ValidationError("email must be a valid email address")
373
+ _email(email)
347
374
  _required_text(password, "password")
348
375
  return cast(LoginResponse, self._request("POST", "/auth/login", json={"email": email, "password": password}, require_auth=False, project_id=None))
349
376
 
377
+ def refresh(self, refresh_token: str) -> TokenPair:
378
+ _required_text(refresh_token, "refresh_token")
379
+ raw = self._request(
380
+ "POST", "/auth/refresh", json={"refresh_token": refresh_token},
381
+ require_auth=False, project_id=None,
382
+ )
383
+ return cast(TokenPair, raw)
384
+
385
+ def logout(self, refresh_token: str) -> None:
386
+ _required_text(refresh_token, "refresh_token")
387
+ self._request(
388
+ "POST", "/auth/logout", json={"refresh_token": refresh_token},
389
+ require_auth=False, project_id=None,
390
+ )
391
+
392
+ def me(self) -> CurrentUserResponse:
393
+ return cast(CurrentUserResponse, self._request("GET", "/auth/me", project_id=None))
394
+
395
+ def logout_all(self) -> None:
396
+ self._request("POST", "/auth/logout-all", project_id=None)
397
+
350
398
  def get_current_plan(self) -> CurrentPlanResponse:
351
399
  return cast(CurrentPlanResponse, self._request("GET", "/org/billing/current-plan"))
352
400
 
@@ -609,14 +657,45 @@ class AsyncControlPlaneClient(_ControlPlaneBase):
609
657
  raw = await self._request("POST", f"/org/api-keys/{_positive_id(key_id, 'key_id')}/test", project_id=_project_override(project_id))
610
658
  return cast(ApiKeyTestResponse, raw)
611
659
 
660
+ async def signup(
661
+ self, email: str, password: str, organization_name: str, *,
662
+ full_name: Optional[str] = None,
663
+ ) -> SignupResponse:
664
+ _signup_fields(email, password, organization_name)
665
+ raw = await self._request(
666
+ "POST", "/auth/signup",
667
+ json=_body(email=email, password=password, organization_name=organization_name, full_name=full_name),
668
+ require_auth=False, project_id=None,
669
+ )
670
+ return cast(SignupResponse, raw)
671
+
612
672
  async def login(self, email: str, password: str) -> LoginResponse:
613
- _required_text(email, "email")
614
- if "@" not in email:
615
- raise ValidationError("email must be a valid email address")
673
+ _email(email)
616
674
  _required_text(password, "password")
617
675
  raw = await self._request("POST", "/auth/login", json={"email": email, "password": password}, require_auth=False, project_id=None)
618
676
  return cast(LoginResponse, raw)
619
677
 
678
+ async def refresh(self, refresh_token: str) -> TokenPair:
679
+ _required_text(refresh_token, "refresh_token")
680
+ raw = await self._request(
681
+ "POST", "/auth/refresh", json={"refresh_token": refresh_token},
682
+ require_auth=False, project_id=None,
683
+ )
684
+ return cast(TokenPair, raw)
685
+
686
+ async def logout(self, refresh_token: str) -> None:
687
+ _required_text(refresh_token, "refresh_token")
688
+ await self._request(
689
+ "POST", "/auth/logout", json={"refresh_token": refresh_token},
690
+ require_auth=False, project_id=None,
691
+ )
692
+
693
+ async def me(self) -> CurrentUserResponse:
694
+ return cast(CurrentUserResponse, await self._request("GET", "/auth/me", project_id=None))
695
+
696
+ async def logout_all(self) -> None:
697
+ await self._request("POST", "/auth/logout-all", project_id=None)
698
+
620
699
  async def get_current_plan(self) -> CurrentPlanResponse:
621
700
  return cast(CurrentPlanResponse, await self._request("GET", "/org/billing/current-plan"))
622
701
 
@@ -38,15 +38,19 @@ class ApiKeyTestResponse(TypedDict, total=False):
38
38
  server_time: str
39
39
 
40
40
 
41
- class LoginTokens(TypedDict):
41
+ class TokenPair(TypedDict):
42
42
  access_token: str
43
43
  refresh_token: str
44
44
  token_type: str
45
45
 
46
46
 
47
+ class LoginTokens(TokenPair):
48
+ pass
49
+
50
+
47
51
  class LoginSession(TypedDict, total=False):
48
52
  user_id: int
49
- organization_id: int
53
+ organization_id: Optional[int]
50
54
  role: str
51
55
 
52
56
 
@@ -57,6 +61,21 @@ class LoginResponse(TypedDict, total=False):
57
61
  mfa_setup_required: bool
58
62
 
59
63
 
64
+ class SignupResponse(TypedDict):
65
+ message: str
66
+ email: str
67
+ requires_verification: bool
68
+
69
+
70
+ class CurrentUserResponse(TypedDict, total=False):
71
+ user_id: str
72
+ role: Optional[str]
73
+ org: Any
74
+ sid: Optional[int]
75
+ oauth_scopes: List[str]
76
+ oauth_app_id: Optional[str]
77
+
78
+
60
79
  class CurrentPlanResponse(TypedDict, total=False):
61
80
  plan: JsonObject
62
81
  status: str
@@ -235,6 +254,17 @@ class LoginRequest(TypedDict):
235
254
  password: str
236
255
 
237
256
 
257
+ class SignupRequest(TypedDict):
258
+ email: str
259
+ password: str
260
+ organization_name: str
261
+ full_name: NotRequired[str]
262
+
263
+
264
+ class RefreshRequest(TypedDict):
265
+ refresh_token: str
266
+
267
+
238
268
  class CreateOrganizationRequest(TypedDict, total=False):
239
269
  name: str
240
270
  domain: str
@@ -1 +0,0 @@
1
- __version__ = "1.5.0"
File without changes
File without changes
File without changes