gomemory 0.1.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.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: gomemory
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the GoMemory AI memory layer
5
+ Author-email: Your Name <your.email@example.com>
6
+ Project-URL: Repository, https://github.com/yourusername/gomemory
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests>=2.31.0
10
+ Requires-Dist: pydantic>=2.0.0
File without changes
@@ -0,0 +1,24 @@
1
+ from .client import GoMemoryClient
2
+ from .exceptions import GoMemoryError, APIError
3
+ from .models import (
4
+ Role,
5
+ MemoryType,
6
+ Message,
7
+ UserResponse,
8
+ MemoryInsertionResponse,
9
+ Memory,
10
+ FullReqStatus
11
+ )
12
+
13
+ __all__ = [
14
+ "GoMemoryClient",
15
+ "GoMemoryError",
16
+ "APIError",
17
+ "Role",
18
+ "MemoryType",
19
+ "Message",
20
+ "UserResponse",
21
+ "MemoryInsertionResponse",
22
+ "Memory",
23
+ "FullReqStatus"
24
+ ]
@@ -0,0 +1,102 @@
1
+ from typing import List, Optional, Union
2
+ import requests
3
+ from pydantic import ValidationError
4
+
5
+ from .exceptions import APIError, GoMemoryError
6
+ from .models import (
7
+ FullReqStatus,
8
+ InsertMemoryRequest,
9
+ Memory,
10
+ MemoryInsertionResponse,
11
+ MemoryRetrievalRequest,
12
+ Message,
13
+ UserResponse
14
+ )
15
+
16
+ class GoMemoryClient:
17
+ def __init__(self, base_url: str):
18
+ self.base_url = base_url.rstrip("/")
19
+ self.session = requests.Session()
20
+
21
+ def _handle_response(self, response: requests.Response):
22
+ """Internal helper to catch APIError structs and raise them as Python exceptions."""
23
+ try:
24
+ data = response.json()
25
+ except ValueError:
26
+ data = response.text
27
+
28
+ if not response.ok:
29
+ # Check if it matches the APIError struct structure
30
+ if isinstance(data, dict) and "Status" in data and "Message" in data:
31
+ raise APIError(
32
+ status=data.get("Status", response.status_code),
33
+ message=data.get("Message", "Unknown error"),
34
+ error_details=str(data.get("Error", ""))
35
+ )
36
+ response.raise_for_status()
37
+
38
+ return data
39
+
40
+ def health_check(self) -> str:
41
+ """GET /health"""
42
+ url = f"{self.base_url}/health"
43
+ response = self.session.get(url)
44
+ # Endpoint returns literal string via writeJSON
45
+ return self._handle_response(response)
46
+
47
+ def create_user(self) -> UserResponse:
48
+ """POST /create/user"""
49
+ url = f"{self.base_url}/create/user"
50
+ response = self.session.post(url)
51
+ data = self._handle_response(response)
52
+ return UserResponse(**data)
53
+
54
+ def add_memory(self, user_id: str, messages: List[Message]) -> MemoryInsertionResponse:
55
+ """POST /add_memory"""
56
+ url = f"{self.base_url}/add_memory"
57
+
58
+ # Pydantic validation on input
59
+ req_data = InsertMemoryRequest(userId=user_id, messages=messages)
60
+
61
+ response = self.session.post(
62
+ url,
63
+ json=req_data.model_dump(by_alias=True)
64
+ )
65
+ data = self._handle_response(response)
66
+ return MemoryInsertionResponse(**data)
67
+
68
+ def get_memory(
69
+ self,
70
+ user_id: str,
71
+ messages: Optional[List[Message]] = None,
72
+ query: Optional[str] = None,
73
+ threshold: Optional[float] = None
74
+ ) -> List[Memory]:
75
+ """POST /get_memory"""
76
+ url = f"{self.base_url}/get_memory"
77
+
78
+ # Pydantic handles the XOR validation for messages/query here
79
+ req_data = MemoryRetrievalRequest(
80
+ userId=user_id,
81
+ messages=messages,
82
+ query=query,
83
+ threshold=threshold
84
+ )
85
+
86
+ response = self.session.post(
87
+ url,
88
+ json=req_data.model_dump(by_alias=True, exclude_none=True)
89
+ )
90
+ data = self._handle_response(response)
91
+
92
+ # Expected to return a list of memories on success
93
+ if isinstance(data, list):
94
+ return [Memory(**m) for m in data]
95
+ raise GoMemoryError(f"Unexpected response format: {data}")
96
+
97
+ def get_status(self, req_id: str) -> FullReqStatus:
98
+ """GET /get_status/{id}"""
99
+ url = f"{self.base_url}/get_status/{req_id}"
100
+ response = self.session.get(url)
101
+ data = self._handle_response(response)
102
+ return FullReqStatus(**data)
@@ -0,0 +1,11 @@
1
+ class GoMemoryError(Exception):
2
+ """Base exception for the GoMemory SDK."""
3
+ pass
4
+
5
+ class APIError(GoMemoryError):
6
+ """Exception raised when the server returns an APIError struct."""
7
+ def __init__(self, status: int, message: str, error_details: str = ""):
8
+ self.status = status
9
+ self.message = message
10
+ self.error_details = error_details
11
+ super().__init__(f"HTTP {status} - {message} ({error_details})")
@@ -0,0 +1,55 @@
1
+ from enum import Enum
2
+ from typing import List, Optional
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+ class Role(str, Enum):
6
+ USER = "user"
7
+ ASSISTANT = "model"
8
+ SYSTEM = "system"
9
+
10
+ class MemoryType(str, Enum):
11
+ # Add actual memory types based on your Go definitions
12
+ CORE = "core"
13
+ GENERAL = "general"
14
+
15
+ class Message(BaseModel):
16
+ role: Role
17
+ content: str
18
+
19
+ class UserResponse(BaseModel):
20
+ user_id: str = Field(alias="userId")
21
+
22
+ class InsertMemoryRequest(BaseModel):
23
+ user_id: str = Field(alias="userId")
24
+ messages: List[Message]
25
+
26
+ class MemoryInsertionResponse(BaseModel):
27
+ req_id: str = Field(alias="ReqId")
28
+ msg: str = Field(alias="Msg")
29
+
30
+ class MemoryRetrievalRequest(BaseModel):
31
+ user_id: str = Field(alias="userId")
32
+ messages: Optional[List[Message]] = None
33
+ query: Optional[str] = None
34
+ threshold: Optional[float] = None
35
+
36
+ @model_validator(mode='after')
37
+ def check_query_or_messages(self):
38
+ # Enforces XOR logic: exactly one must be provided, but not both.
39
+ has_messages = bool(self.messages)
40
+ has_query = bool(self.query)
41
+
42
+ if has_messages == has_query:
43
+ raise ValueError("Exactly one of 'messages' or 'query' must be provided. Cannot provide both or neither.")
44
+ return self
45
+
46
+ class Memory(BaseModel):
47
+ memory_text: str = Field(alias="Memory_text")
48
+ type: str = Field(alias="Type") # Or MemoryType if enum is strictly enforced
49
+ memory_id: str = Field(alias="Memory_Id")
50
+ user_id: str = Field(alias="UserId")
51
+
52
+ class FullReqStatus(BaseModel):
53
+ status: str # Assuming types.ReqStatus resolves to a string. Use Enum if strict.
54
+ error: Optional[str] = None
55
+ created_at: str = Field(alias="createdAt")
File without changes
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: gomemory
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the GoMemory AI memory layer
5
+ Author-email: Your Name <your.email@example.com>
6
+ Project-URL: Repository, https://github.com/yourusername/gomemory
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests>=2.31.0
10
+ Requires-Dist: pydantic>=2.0.0
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ gomemory/__init__.py
4
+ gomemory/client.py
5
+ gomemory/exceptions.py
6
+ gomemory/models.py
7
+ gomemory/py.typed
8
+ gomemory.egg-info/PKG-INFO
9
+ gomemory.egg-info/SOURCES.txt
10
+ gomemory.egg-info/dependency_links.txt
11
+ gomemory.egg-info/requires.txt
12
+ gomemory.egg-info/top_level.txt
13
+ tests/test_client.py
@@ -0,0 +1,2 @@
1
+ requests>=2.31.0
2
+ pydantic>=2.0.0
@@ -0,0 +1 @@
1
+ gomemory
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gomemory"
7
+ version = "0.1.0"
8
+ description = "Python SDK for the GoMemory AI memory layer"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ authors = [
12
+ {name = "Your Name", email = "your.email@example.com"}
13
+ ]
14
+ dependencies = [
15
+ "requests>=2.31.0",
16
+ "pydantic>=2.0.0"
17
+ ]
18
+
19
+ [project.urls]
20
+ Repository = "https://github.com/yourusername/gomemory" # Update this to your actual GitHub repo
21
+
22
+ [tool.setuptools.packages.find]
23
+ include = ["gomemory*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,65 @@
1
+ import os
2
+ import pytest
3
+ from gomemory import GoMemoryClient, Role, Message
4
+ from gomemory.exceptions import APIError
5
+ from pydantic import ValidationError
6
+
7
+ # Default to localhost if not set in the environment
8
+ BASE_URL = os.getenv("GOMEMORY_BASE_URL", "http://localhost:9000")
9
+
10
+ @pytest.fixture(scope="module")
11
+ def client():
12
+ return GoMemoryClient(base_url=BASE_URL)
13
+
14
+ def test_health_check(client):
15
+ response = client.health_check()
16
+ assert response == "Server is healthy!"
17
+
18
+ def test_create_user(client):
19
+ response = client.create_user()
20
+ assert response.user_id is not None
21
+ assert isinstance(response.user_id, str)
22
+
23
+ def test_add_memory(client):
24
+ # Setup: need a user first
25
+ user = client.create_user()
26
+
27
+ messages = [
28
+ Message(role=Role.USER, content="Hey man what's up! My name is mario .. my brother's name is Wario!"),
29
+ Message(role=Role.ASSISTANT, content="I will remember that.")
30
+ ]
31
+
32
+ response = client.add_memory(user_id=user.user_id, messages=messages)
33
+ assert response.req_id is not None
34
+ assert response.msg is not None
35
+
36
+ def test_get_memory_validation(client):
37
+ # Test the Pydantic XOR validation (should fail before hitting the server)
38
+ with pytest.raises(ValidationError) as exc_info:
39
+ client.get_memory(
40
+ user_id="4bdc091b-eaa5-4d42-bbba-3cd798b9d294",
41
+ )
42
+ assert "Exactly one of 'messages' or 'query' must be provided. Cannot provide both or neither." in str(exc_info.value)
43
+
44
+ def test_get_memory_success(client):
45
+ user = client.create_user()
46
+
47
+ # Optional: Wait for your Go server's worker pool to process embeddings
48
+ # if add_memory is asynchronous before calling get_memory.
49
+
50
+ # Using query
51
+ memories = client.get_memory(
52
+ user_id="4bdc091b-eaa5-4d42-bbba-3cd798b9d294",
53
+ query="I like dogs",
54
+ threshold=0.7
55
+ )
56
+ assert isinstance(memories, list)
57
+
58
+ def test_get_status(client):
59
+ user = client.create_user()
60
+ messages = [Message(role=Role.USER, content="Test memory status")]
61
+ insert_res = client.add_memory(user_id=user.user_id, messages=messages)
62
+
63
+ status_res = client.get_status(req_id=insert_res.req_id)
64
+ assert status_res.status is not None
65
+ assert status_res.created_at is not None