sovant 1.1.0__tar.gz → 1.3.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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sovant
3
- Version: 1.1.0
3
+ Version: 1.3.0
4
4
  Summary: Sovant Memory-as-a-Service Python SDK
5
5
  Author: Sovant
6
6
  License: MIT
@@ -16,7 +16,8 @@ Dynamic: license-file
16
16
 
17
17
  # Sovant Python SDK
18
18
 
19
- Sovant is Memory-as-a-Service: a durable, queryable memory layer for AI apps with cross-model recall, hybrid (semantic + deterministic) retrieval, and simple SDKs.
19
+ **Sovant is a governed AI memory layer for AI agents and applications.**
20
+ Use it to store, search, and recall memories with profile awareness and enterprise-grade control over how memory is captured and used.
20
21
 
21
22
  [![PyPI version](https://img.shields.io/pypi/v/sovant.svg)](https://pypi.org/project/sovant/)
22
23
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -57,6 +58,94 @@ updated = client.memory.update(mem["id"], {
57
58
  client.memory.delete(mem["id"])
58
59
  ```
59
60
 
61
+ ## Recall vs Search
62
+
63
+ Sovant provides two ways to query memories:
64
+
65
+ - **`memory_recall()`** – Hybrid recall, profile-aware
66
+ Use for conversational queries: "What do you know about me?", "What happened on Project X?".
67
+ Uses Sovant's hybrid pipeline (profile fast-path + thread-scoped lexical + vector semantic search) and prioritizes profile facts (name/age/location) when available.
68
+
69
+ - **`memory_search()`** – Semantic search
70
+ Use for topic lookup and discovery. Pure vector similarity search without profile logic.
71
+ Behavior unchanged from previous versions.
72
+
73
+ ```python
74
+ # Recall for conversational queries
75
+ context = client.memory_recall(
76
+ query="what do you know about me?",
77
+ limit=10
78
+ )
79
+
80
+ # Search for topic discovery
81
+ topics = client.memory_search({
82
+ "query": "project updates",
83
+ "limit": 5
84
+ })
85
+ ```
86
+
87
+ ## Working with Threads
88
+
89
+ Threads let you organize related memories into conversations or sessions. Each thread has a `title` and can contain multiple memories.
90
+
91
+ ```python
92
+ from sovant import Sovant
93
+
94
+ client = Sovant(api_key="sk_live_your_api_key_here")
95
+
96
+ # Create a new thread
97
+ thread = client.threads_create(
98
+ title="Project Alpha Discussion",
99
+ description="Q1 planning meeting notes",
100
+ metadata={"project": "alpha", "quarter": "Q1"}
101
+ )
102
+
103
+ # Store memories in the thread
104
+ from sovant.models import MemoryCreate
105
+
106
+ mem1 = client.memory_create(MemoryCreate(
107
+ data="Decided to launch in March",
108
+ type="journal",
109
+ thread_id=thread["id"]
110
+ ))
111
+
112
+ mem2 = client.memory_create(MemoryCreate(
113
+ data="Budget approved: $50k",
114
+ type="insight",
115
+ thread_id=thread["id"]
116
+ ))
117
+
118
+ # Recall memories from this specific thread
119
+ thread_memories = client.memory_recall(
120
+ query="launch date",
121
+ thread_id=thread["id"],
122
+ limit=10
123
+ )
124
+
125
+ # Get thread with all its memories
126
+ thread_with_memories = client.threads_get(
127
+ thread["id"],
128
+ include_memories=True,
129
+ limit=50
130
+ )
131
+
132
+ # List all threads
133
+ threads = client.threads_list(limit=20, offset=0)
134
+
135
+ # Update thread
136
+ updated = client.threads_update(
137
+ thread["id"],
138
+ title="Project Alpha - Q1 Launch",
139
+ status="completed"
140
+ )
141
+
142
+ # Delete thread (keeps memories by default)
143
+ client.threads_delete(thread["id"])
144
+
145
+ # Delete thread AND all its memories
146
+ client.threads_delete(thread["id"], delete_memories=True)
147
+ ```
148
+
60
149
  ## Chat in 60 Seconds
61
150
 
62
151
  Stream real-time chat responses with memory context:
@@ -1,6 +1,7 @@
1
1
  # Sovant Python SDK
2
2
 
3
- Sovant is Memory-as-a-Service: a durable, queryable memory layer for AI apps with cross-model recall, hybrid (semantic + deterministic) retrieval, and simple SDKs.
3
+ **Sovant is a governed AI memory layer for AI agents and applications.**
4
+ Use it to store, search, and recall memories with profile awareness and enterprise-grade control over how memory is captured and used.
4
5
 
5
6
  [![PyPI version](https://img.shields.io/pypi/v/sovant.svg)](https://pypi.org/project/sovant/)
6
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -41,6 +42,94 @@ updated = client.memory.update(mem["id"], {
41
42
  client.memory.delete(mem["id"])
42
43
  ```
43
44
 
45
+ ## Recall vs Search
46
+
47
+ Sovant provides two ways to query memories:
48
+
49
+ - **`memory_recall()`** – Hybrid recall, profile-aware
50
+ Use for conversational queries: "What do you know about me?", "What happened on Project X?".
51
+ Uses Sovant's hybrid pipeline (profile fast-path + thread-scoped lexical + vector semantic search) and prioritizes profile facts (name/age/location) when available.
52
+
53
+ - **`memory_search()`** – Semantic search
54
+ Use for topic lookup and discovery. Pure vector similarity search without profile logic.
55
+ Behavior unchanged from previous versions.
56
+
57
+ ```python
58
+ # Recall for conversational queries
59
+ context = client.memory_recall(
60
+ query="what do you know about me?",
61
+ limit=10
62
+ )
63
+
64
+ # Search for topic discovery
65
+ topics = client.memory_search({
66
+ "query": "project updates",
67
+ "limit": 5
68
+ })
69
+ ```
70
+
71
+ ## Working with Threads
72
+
73
+ Threads let you organize related memories into conversations or sessions. Each thread has a `title` and can contain multiple memories.
74
+
75
+ ```python
76
+ from sovant import Sovant
77
+
78
+ client = Sovant(api_key="sk_live_your_api_key_here")
79
+
80
+ # Create a new thread
81
+ thread = client.threads_create(
82
+ title="Project Alpha Discussion",
83
+ description="Q1 planning meeting notes",
84
+ metadata={"project": "alpha", "quarter": "Q1"}
85
+ )
86
+
87
+ # Store memories in the thread
88
+ from sovant.models import MemoryCreate
89
+
90
+ mem1 = client.memory_create(MemoryCreate(
91
+ data="Decided to launch in March",
92
+ type="journal",
93
+ thread_id=thread["id"]
94
+ ))
95
+
96
+ mem2 = client.memory_create(MemoryCreate(
97
+ data="Budget approved: $50k",
98
+ type="insight",
99
+ thread_id=thread["id"]
100
+ ))
101
+
102
+ # Recall memories from this specific thread
103
+ thread_memories = client.memory_recall(
104
+ query="launch date",
105
+ thread_id=thread["id"],
106
+ limit=10
107
+ )
108
+
109
+ # Get thread with all its memories
110
+ thread_with_memories = client.threads_get(
111
+ thread["id"],
112
+ include_memories=True,
113
+ limit=50
114
+ )
115
+
116
+ # List all threads
117
+ threads = client.threads_list(limit=20, offset=0)
118
+
119
+ # Update thread
120
+ updated = client.threads_update(
121
+ thread["id"],
122
+ title="Project Alpha - Q1 Launch",
123
+ status="completed"
124
+ )
125
+
126
+ # Delete thread (keeps memories by default)
127
+ client.threads_delete(thread["id"])
128
+
129
+ # Delete thread AND all its memories
130
+ client.threads_delete(thread["id"], delete_memories=True)
131
+ ```
132
+
44
133
  ## Chat in 60 Seconds
45
134
 
46
135
  Stream real-time chat responses with memory context:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sovant"
3
- version = "1.1.0"
3
+ version = "1.3.0"
4
4
  description = "Sovant Memory-as-a-Service Python SDK"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,4 +1,4 @@
1
1
  from .client import Sovant, SovantError
2
2
  from .models import MemoryCreate, MemoryResult, SearchQuery
3
3
 
4
- __version__ = "0.1.0"
4
+ __version__ = "1.3.0"
@@ -131,7 +131,7 @@ class Sovant:
131
131
 
132
132
  def memory_create(self, create: MemoryCreate):
133
133
  # Convert data field to content field for API
134
- body = create.model_dump()
134
+ body = create.model_dump(exclude_none=True)
135
135
  if 'data' in body:
136
136
  body['content'] = json.dumps(body.pop('data')) if not isinstance(body.get('data'), str) else body.pop('data')
137
137
 
@@ -162,9 +162,27 @@ class Sovant:
162
162
  params['to_date'] = q.to_date
163
163
  return self._request("GET", f"{self.base_url}/api/v1/memory/search", params=params)
164
164
 
165
- def memory_recall(self, q: SearchQuery):
166
- """Semantic search alias for memory_search()"""
167
- return self.memory_search(q)
165
+ def memory_recall(self, query: str, thread_id: str | None = None, limit: int | None = None):
166
+ """
167
+ Hybrid recall with profile awareness
168
+
169
+ Uses multi-stage pipeline (profile fast-path + lexical + semantic)
170
+ Guarantees profile facts (name/age/location) when available
171
+
172
+ Use recall() for conversational queries ("who am I?", "what do you know about me?")
173
+ Use memory_search() for pure semantic topic lookup
174
+
175
+ Args:
176
+ query: The search query (required)
177
+ thread_id: Optional thread context for thread-scoped recall
178
+ limit: Maximum results to return (default 8, max 50)
179
+ """
180
+ params = {'query': query}
181
+ if thread_id:
182
+ params['thread_id'] = thread_id
183
+ if limit:
184
+ params['limit'] = str(limit)
185
+ return self._request("GET", f"{self.base_url}/api/v1/memory/recall", params=params)
168
186
 
169
187
  def memory_update(self, id: str, patch: Dict[str, Any]):
170
188
  # Convert data field to content field if present
@@ -199,4 +217,108 @@ class Sovant:
199
217
  "data": data
200
218
  })
201
219
 
202
- return self._request("POST", f"{self.base_url}/api/v1/memory/batch", json=operations)
220
+ return self._request("POST", f"{self.base_url}/api/v1/memory/batch", json=operations)
221
+
222
+ # ==================== Thread Methods ====================
223
+
224
+ def threads_create(self, title: str, description: str | None = None, metadata: Dict[str, Any] | None = None):
225
+ """
226
+ Create a new thread
227
+
228
+ Args:
229
+ title: Thread title (required)
230
+ description: Optional thread description
231
+ metadata: Optional metadata dictionary
232
+
233
+ Returns:
234
+ Created thread object with id
235
+ """
236
+ body = {"title": title}
237
+ if description:
238
+ body["description"] = description
239
+ if metadata:
240
+ body["metadata"] = metadata
241
+ return self._request("POST", f"{self.base_url}/api/v1/threads", json=body)
242
+
243
+ def threads_list(self, limit: int = 20, offset: int = 0, status: str | None = None):
244
+ """
245
+ List threads with pagination
246
+
247
+ Args:
248
+ limit: Maximum number of threads to return (default: 20)
249
+ offset: Number of threads to skip (default: 0)
250
+ status: Filter by status: 'active', 'archived', or 'completed'
251
+
252
+ Returns:
253
+ Paginated list of threads
254
+ """
255
+ params = {"limit": str(limit), "offset": str(offset)}
256
+ if status:
257
+ params["status"] = status
258
+ return self._request("GET", f"{self.base_url}/api/v1/threads", params=params)
259
+
260
+ def threads_get(self, thread_id: str, include_memories: bool = False, limit: int = 50):
261
+ """
262
+ Get a thread by ID
263
+
264
+ Args:
265
+ thread_id: Thread UUID
266
+ include_memories: If True, include full memory objects (default: False)
267
+ limit: Maximum number of memories to include (default: 50)
268
+
269
+ Returns:
270
+ Thread object with optional memories
271
+ """
272
+ params = {}
273
+ if include_memories:
274
+ params["include_memories"] = "true"
275
+ params["limit"] = str(limit)
276
+ return self._request("GET", f"{self.base_url}/api/v1/threads/{thread_id}", params=params)
277
+
278
+ def threads_update(
279
+ self,
280
+ thread_id: str,
281
+ title: str | None = None,
282
+ description: str | None = None,
283
+ status: str | None = None,
284
+ metadata: Dict[str, Any] | None = None
285
+ ):
286
+ """
287
+ Update a thread
288
+
289
+ Args:
290
+ thread_id: Thread UUID
291
+ title: New title
292
+ description: New description
293
+ status: New status ('active', 'archived', or 'completed')
294
+ metadata: New metadata dictionary
295
+
296
+ Returns:
297
+ Updated thread object
298
+ """
299
+ body = {}
300
+ if title is not None:
301
+ body["title"] = title
302
+ if description is not None:
303
+ body["description"] = description
304
+ if status is not None:
305
+ body["status"] = status
306
+ if metadata is not None:
307
+ body["metadata"] = metadata
308
+ return self._request("PUT", f"{self.base_url}/api/v1/threads/{thread_id}", json=body)
309
+
310
+ def threads_delete(self, thread_id: str, delete_memories: bool = False):
311
+ """
312
+ Delete a thread
313
+
314
+ Args:
315
+ thread_id: Thread UUID
316
+ delete_memories: If True, also delete all associated memories (default: False)
317
+
318
+ Returns:
319
+ Deletion confirmation
320
+ """
321
+ params = {}
322
+ if delete_memories:
323
+ params["delete_memories"] = "true"
324
+ return self._request("DELETE", f"{self.base_url}/api/v1/threads/{thread_id}", params=params)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sovant
3
- Version: 1.1.0
3
+ Version: 1.3.0
4
4
  Summary: Sovant Memory-as-a-Service Python SDK
5
5
  Author: Sovant
6
6
  License: MIT
@@ -16,7 +16,8 @@ Dynamic: license-file
16
16
 
17
17
  # Sovant Python SDK
18
18
 
19
- Sovant is Memory-as-a-Service: a durable, queryable memory layer for AI apps with cross-model recall, hybrid (semantic + deterministic) retrieval, and simple SDKs.
19
+ **Sovant is a governed AI memory layer for AI agents and applications.**
20
+ Use it to store, search, and recall memories with profile awareness and enterprise-grade control over how memory is captured and used.
20
21
 
21
22
  [![PyPI version](https://img.shields.io/pypi/v/sovant.svg)](https://pypi.org/project/sovant/)
22
23
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -57,6 +58,94 @@ updated = client.memory.update(mem["id"], {
57
58
  client.memory.delete(mem["id"])
58
59
  ```
59
60
 
61
+ ## Recall vs Search
62
+
63
+ Sovant provides two ways to query memories:
64
+
65
+ - **`memory_recall()`** – Hybrid recall, profile-aware
66
+ Use for conversational queries: "What do you know about me?", "What happened on Project X?".
67
+ Uses Sovant's hybrid pipeline (profile fast-path + thread-scoped lexical + vector semantic search) and prioritizes profile facts (name/age/location) when available.
68
+
69
+ - **`memory_search()`** – Semantic search
70
+ Use for topic lookup and discovery. Pure vector similarity search without profile logic.
71
+ Behavior unchanged from previous versions.
72
+
73
+ ```python
74
+ # Recall for conversational queries
75
+ context = client.memory_recall(
76
+ query="what do you know about me?",
77
+ limit=10
78
+ )
79
+
80
+ # Search for topic discovery
81
+ topics = client.memory_search({
82
+ "query": "project updates",
83
+ "limit": 5
84
+ })
85
+ ```
86
+
87
+ ## Working with Threads
88
+
89
+ Threads let you organize related memories into conversations or sessions. Each thread has a `title` and can contain multiple memories.
90
+
91
+ ```python
92
+ from sovant import Sovant
93
+
94
+ client = Sovant(api_key="sk_live_your_api_key_here")
95
+
96
+ # Create a new thread
97
+ thread = client.threads_create(
98
+ title="Project Alpha Discussion",
99
+ description="Q1 planning meeting notes",
100
+ metadata={"project": "alpha", "quarter": "Q1"}
101
+ )
102
+
103
+ # Store memories in the thread
104
+ from sovant.models import MemoryCreate
105
+
106
+ mem1 = client.memory_create(MemoryCreate(
107
+ data="Decided to launch in March",
108
+ type="journal",
109
+ thread_id=thread["id"]
110
+ ))
111
+
112
+ mem2 = client.memory_create(MemoryCreate(
113
+ data="Budget approved: $50k",
114
+ type="insight",
115
+ thread_id=thread["id"]
116
+ ))
117
+
118
+ # Recall memories from this specific thread
119
+ thread_memories = client.memory_recall(
120
+ query="launch date",
121
+ thread_id=thread["id"],
122
+ limit=10
123
+ )
124
+
125
+ # Get thread with all its memories
126
+ thread_with_memories = client.threads_get(
127
+ thread["id"],
128
+ include_memories=True,
129
+ limit=50
130
+ )
131
+
132
+ # List all threads
133
+ threads = client.threads_list(limit=20, offset=0)
134
+
135
+ # Update thread
136
+ updated = client.threads_update(
137
+ thread["id"],
138
+ title="Project Alpha - Q1 Launch",
139
+ status="completed"
140
+ )
141
+
142
+ # Delete thread (keeps memories by default)
143
+ client.threads_delete(thread["id"])
144
+
145
+ # Delete thread AND all its memories
146
+ client.threads_delete(thread["id"], delete_memories=True)
147
+ ```
148
+
60
149
  ## Chat in 60 Seconds
61
150
 
62
151
  Stream real-time chat responses with memory context:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes