sovant 1.3.0__py3-none-any.whl → 1.3.2__py3-none-any.whl

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.
sovant/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  from .client import Sovant, SovantError
2
2
  from .models import MemoryCreate, MemoryResult, SearchQuery
3
3
 
4
- __version__ = "1.3.0"
4
+ __version__ = "1.3.2"
sovant/client.py CHANGED
@@ -193,6 +193,61 @@ class Sovant:
193
193
  def memory_delete(self, id: str):
194
194
  return self._request("DELETE", f"{self.base_url}/api/v1/memories/{id}")
195
195
 
196
+ def memory_list(
197
+ self,
198
+ limit: int | None = None,
199
+ offset: int | None = None,
200
+ thread_id: str | None = None,
201
+ type: str | None = None,
202
+ tags: list[str] | None = None,
203
+ is_pinned: bool | None = None,
204
+ is_archived: bool | None = None,
205
+ sort_by: str | None = None,
206
+ sort_order: str | None = None,
207
+ ):
208
+ """
209
+ List memories with filtering and pagination
210
+
211
+ Returns memories ordered by sort criteria (default: created_at desc).
212
+ Use list() to fetch recent memories or filter by criteria.
213
+ Use memory_search() for semantic/vector-based queries.
214
+ Use memory_recall() for conversational AI queries.
215
+
216
+ Args:
217
+ limit: Maximum memories to return (default: 20, max: 100)
218
+ offset: Number of memories to skip for pagination (default: 0)
219
+ thread_id: Filter by thread ID
220
+ type: Filter by memory type ('journal', 'insight', 'observation', 'task', 'preference')
221
+ tags: Filter by tags (memories must have all specified tags)
222
+ is_pinned: Filter by pinned status
223
+ is_archived: Filter by archived status
224
+ sort_by: Sort field ('created_at', 'updated_at', 'importance', 'type')
225
+ sort_order: Sort direction ('asc' or 'desc')
226
+
227
+ Returns:
228
+ Dict with 'memories', 'total', 'limit', 'offset', 'has_more'
229
+ """
230
+ params = {}
231
+ if limit is not None:
232
+ params['limit'] = str(limit)
233
+ if offset is not None:
234
+ params['offset'] = str(offset)
235
+ if thread_id:
236
+ params['thread_id'] = thread_id
237
+ if type:
238
+ params['type'] = type
239
+ if tags:
240
+ params['tags'] = ','.join(tags)
241
+ if is_pinned is not None:
242
+ params['is_pinned'] = str(is_pinned).lower()
243
+ if is_archived is not None:
244
+ params['is_archived'] = str(is_archived).lower()
245
+ if sort_by:
246
+ params['sort_by'] = sort_by
247
+ if sort_order:
248
+ params['sort_order'] = sort_order
249
+ return self._request("GET", f"{self.base_url}/api/v1/memory", params=params)
250
+
196
251
  def memory_create_batch(self, memories: list[Dict[str, Any]]):
197
252
  """
198
253
  Batch create multiple memories in a single request
@@ -0,0 +1,417 @@
1
+ Metadata-Version: 2.4
2
+ Name: sovant
3
+ Version: 1.3.2
4
+ Summary: Sovant Python SDK — governed AI memory layer for AI agents and applications
5
+ Author: Sovant
6
+ License-Expression: MIT
7
+ Project-URL: Documentation, https://sovant.ai/docs
8
+ Project-URL: Source, https://github.com/hechin91/sovant-ai
9
+ Project-URL: Tracker, https://github.com/hechin91/sovant-ai/issues
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: httpx>=0.27.0
14
+ Requires-Dist: pydantic>=2.8.2
15
+ Dynamic: license-file
16
+
17
+ # Sovant Python SDK
18
+
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.
21
+
22
+ [![PyPI version](https://img.shields.io/pypi/v/sovant.svg)](https://pypi.org/project/sovant/)
23
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install sovant
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```python
34
+ import os
35
+ from sovant import Sovant, MemoryCreate, SearchQuery
36
+
37
+ client = Sovant(api_key=os.environ["SOVANT_API_KEY"])
38
+
39
+ # Create a memory
40
+ mem = client.memory_create(MemoryCreate(
41
+ data="User prefers dark mode",
42
+ type="preference",
43
+ tags=["ui", "settings"],
44
+ ))
45
+
46
+ # Search memories
47
+ results = client.memory_search(SearchQuery(
48
+ query="user preferences",
49
+ limit=10,
50
+ ))
51
+
52
+ # Update a memory
53
+ updated = client.memory_update(mem["id"], {
54
+ "tags": ["ui", "settings", "theme"],
55
+ })
56
+
57
+ # Delete a memory
58
+ client.memory_delete(mem["id"])
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
+
72
+ ```python
73
+ # Recall for conversational queries (returns { "results": [...], "total": N })
74
+ recall = client.memory_recall(
75
+ query="what do you know about me?",
76
+ limit=10,
77
+ )
78
+ for mem in recall.get("results", []):
79
+ print(mem["content"])
80
+
81
+ # Search for topic discovery
82
+ topics = client.memory_search(SearchQuery(
83
+ query="project updates",
84
+ limit=5,
85
+ ))
86
+ ```
87
+
88
+ ## Working with Threads
89
+
90
+ Threads let you organize related memories into conversations or sessions. Each thread has a `title` and can contain multiple memories.
91
+
92
+ ```python
93
+ import os
94
+ from sovant import Sovant, MemoryCreate
95
+
96
+ client = Sovant(api_key=os.environ["SOVANT_API_KEY"])
97
+
98
+ # Create a new thread
99
+ thread = client.threads_create(
100
+ title="Project Alpha Discussion",
101
+ description="Q1 planning meeting notes",
102
+ metadata={"project": "alpha", "quarter": "Q1"},
103
+ )
104
+
105
+ # Store memories in the thread
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_recall = client.memory_recall(
120
+ query="launch date",
121
+ thread_id=thread["id"],
122
+ limit=10,
123
+ )
124
+ # thread_recall["results"] contains the matching memories
125
+
126
+ # Get thread with all its memories
127
+ thread_with_memories = client.threads_get(
128
+ thread["id"],
129
+ include_memories=True,
130
+ limit=50,
131
+ )
132
+
133
+ # List all threads
134
+ threads = client.threads_list(limit=20, offset=0)
135
+
136
+ # Update thread
137
+ updated = client.threads_update(
138
+ thread["id"],
139
+ title="Project Alpha - Q1 Launch",
140
+ status="completed",
141
+ )
142
+
143
+ # Delete thread (keeps memories by default)
144
+ client.threads_delete(thread["id"])
145
+
146
+ # Delete thread AND all its memories
147
+ client.threads_delete(thread["id"], delete_memories=True)
148
+ ```
149
+
150
+ ## Configuration
151
+
152
+ ```python
153
+ from sovant import Sovant
154
+
155
+ client = Sovant(
156
+ api_key="sk_live_...", # Required (or set SOVANT_API_KEY env var)
157
+ base_url="https://sovant.ai", # Optional, defaults to https://sovant.ai
158
+ timeout=30.0, # Optional, request timeout in seconds (default: 30.0)
159
+ max_retries=3, # Optional, max retry attempts (default: 3)
160
+ )
161
+ ```
162
+
163
+ The SDK handles authentication via the `Authorization: Bearer` header.
164
+
165
+ ## API Reference
166
+
167
+ ### Memory Operations
168
+
169
+ #### Create Memory
170
+
171
+ ```python
172
+ from sovant import MemoryCreate
173
+
174
+ memory = client.memory_create(MemoryCreate(
175
+ data="Customer contacted support about billing",
176
+ type="observation", # 'journal' | 'insight' | 'observation' | 'task' | 'preference'
177
+ tags=["support", "billing"],
178
+ metadata={"ticket_id": "12345"},
179
+ thread_id="thread_abc123", # Optional thread association
180
+ ))
181
+ ```
182
+
183
+ #### Get Memory by ID
184
+
185
+ ```python
186
+ memory = client.memory_get("mem_123abc")
187
+ ```
188
+
189
+ #### Update Memory
190
+
191
+ ```python
192
+ updated = client.memory_update("mem_123abc", {
193
+ "tags": ["support", "billing", "resolved"],
194
+ })
195
+ ```
196
+
197
+ #### Delete Memory
198
+
199
+ ```python
200
+ client.memory_delete("mem_123abc")
201
+ ```
202
+
203
+ #### Search Memories
204
+
205
+ ```python
206
+ from sovant import SearchQuery
207
+
208
+ # Semantic search
209
+ results = client.memory_search(SearchQuery(
210
+ query="customer preferences about notifications",
211
+ limit=10,
212
+ type="preference",
213
+ ))
214
+
215
+ # Filter-based search
216
+ results = client.memory_search(SearchQuery(
217
+ tags=["settings", "notifications"],
218
+ from_date="2024-01-01",
219
+ to_date="2024-12-31",
220
+ limit=20,
221
+ ))
222
+ ```
223
+
224
+ #### Recall Memories
225
+
226
+ Recall returns `{ "results": [...], "total": N, "query_type": "hybrid" }`.
227
+
228
+ ```python
229
+ # Hybrid recall with profile awareness
230
+ recall = client.memory_recall(
231
+ query="what do you know about me?",
232
+ limit=10,
233
+ )
234
+ for mem in recall.get("results", []):
235
+ print(mem["content"], mem.get("relevance"))
236
+
237
+ # Thread-scoped recall
238
+ recall = client.memory_recall(
239
+ query="launch timeline",
240
+ thread_id="thread_abc123",
241
+ limit=5,
242
+ )
243
+ ```
244
+
245
+ #### Batch Create
246
+
247
+ ```python
248
+ results = client.memory_create_batch([
249
+ {"data": "First memory", "type": "journal"},
250
+ {"data": "Second memory", "type": "insight", "tags": ["important"]},
251
+ ])
252
+ ```
253
+
254
+ #### List Memories
255
+
256
+ Fetch memories with filtering and pagination. Use `memory_list()` to retrieve recent memories or filter by criteria — it's more efficient than `memory_search()` when you don't need vector similarity.
257
+
258
+ ```python
259
+ # List recent memories
260
+ result = client.memory_list(limit=20, offset=0)
261
+ for mem in result["memories"]:
262
+ print(mem["content"])
263
+
264
+ # Filter by thread
265
+ thread_mems = client.memory_list(thread_id="thread-uuid", limit=50)
266
+
267
+ # Filter by type and tags
268
+ prefs = client.memory_list(
269
+ type="preference",
270
+ tags=["settings"],
271
+ sort_by="updated_at",
272
+ sort_order="desc",
273
+ )
274
+
275
+ # Pinned memories only
276
+ pinned = client.memory_list(is_pinned=True)
277
+ ```
278
+
279
+ **Available parameters:**
280
+ - `limit` — max results (default: 20, max: 100)
281
+ - `offset` — pagination offset
282
+ - `thread_id` — filter by thread
283
+ - `type` — filter by memory type
284
+ - `tags` — filter by tags (must have all)
285
+ - `is_pinned` — filter by pinned status
286
+ - `is_archived` — filter by archived status
287
+ - `sort_by` — `created_at`, `updated_at`, `importance`, or `type`
288
+ - `sort_order` — `asc` or `desc`
289
+
290
+ ### Thread Management
291
+
292
+ ```python
293
+ # Create a thread
294
+ thread = client.threads_create(
295
+ title="Customer Support Session",
296
+ metadata={"user_id": "user_123"},
297
+ )
298
+
299
+ # List threads
300
+ threads = client.threads_list(limit=10, offset=0)
301
+
302
+ # Get thread by ID (with memories)
303
+ thread = client.threads_get("thread_abc123", include_memories=True)
304
+
305
+ # Update thread
306
+ updated = client.threads_update(
307
+ "thread_abc123",
308
+ title="Resolved: Billing Issue",
309
+ status="completed",
310
+ )
311
+
312
+ # Delete thread
313
+ client.threads_delete("thread_abc123")
314
+ ```
315
+
316
+ ## Memory Types
317
+
318
+ - **journal** -- Chronological entries and logs
319
+ - **insight** -- Derived patterns and conclusions
320
+ - **observation** -- Factual, observed information
321
+ - **task** -- Action items and todos
322
+ - **preference** -- User preferences and settings
323
+
324
+ ## Error Handling
325
+
326
+ The SDK raises `SovantError` for all API errors:
327
+
328
+ ```python
329
+ from sovant import Sovant, SovantError
330
+
331
+ try:
332
+ memory = client.memory_get("invalid_id")
333
+ except SovantError as e:
334
+ print(f"Error: {e}")
335
+ print(f"Code: {e.code}") # e.g. "NOT_FOUND", "HTTP_401"
336
+ print(f"Status: {e.status}") # e.g. 404, 401
337
+
338
+ if e.status == 404:
339
+ print("Memory not found")
340
+ elif e.status == 401:
341
+ print("Invalid API key")
342
+ elif e.status == 429:
343
+ print("Rate limited -- SDK retries automatically")
344
+ ```
345
+
346
+ The SDK automatically retries on rate limit (429) and server errors (5xx) with exponential backoff.
347
+
348
+ ## Examples
349
+
350
+ ### Customer Support Integration
351
+
352
+ ```python
353
+ from sovant import MemoryCreate
354
+
355
+ # Track customer interaction
356
+ interaction = client.memory_create(MemoryCreate(
357
+ data="Customer reported slow dashboard loading",
358
+ type="observation",
359
+ thread_id=f"ticket_{ticket_id}",
360
+ tags=["support", "performance", "dashboard"],
361
+ metadata={
362
+ "ticket_id": ticket_id,
363
+ "priority": "high",
364
+ },
365
+ ))
366
+
367
+ # Record resolution
368
+ resolution = client.memory_create(MemoryCreate(
369
+ data="Resolved by clearing cache and upgrading plan",
370
+ type="insight",
371
+ thread_id=f"ticket_{ticket_id}",
372
+ tags=["support", "resolved"],
373
+ ))
374
+ ```
375
+
376
+ ### User Preference Tracking
377
+
378
+ ```python
379
+ from sovant import MemoryCreate, SearchQuery
380
+
381
+ # Store preference
382
+ client.memory_create(MemoryCreate(
383
+ data="User prefers email notifications over SMS",
384
+ type="preference",
385
+ tags=["notifications", "email"],
386
+ ))
387
+
388
+ # Query preferences
389
+ preferences = client.memory_search(SearchQuery(
390
+ query="notification preferences",
391
+ type="preference",
392
+ ))
393
+ ```
394
+
395
+ ## Rate Limiting
396
+
397
+ The API enforces 60 requests per minute. The SDK automatically retries rate-limited requests with exponential backoff. Rate limit headers are included in responses:
398
+
399
+ - `X-RateLimit-Limit` -- Request limit per window
400
+ - `X-RateLimit-Remaining` -- Remaining requests
401
+ - `X-RateLimit-Reset` -- Reset timestamp
402
+
403
+ ## Support
404
+
405
+ - Documentation: [https://sovant.ai/docs](https://sovant.ai/docs)
406
+ - Issues: [GitHub Issues](https://github.com/hechin91/sovant-ai/issues)
407
+
408
+ ## License & Use
409
+
410
+ - This SDK is MIT-licensed for integration convenience.
411
+ - The Sovant API and platform are proprietary to Sovant Technologies Sdn. Bhd.
412
+ - You may use this SDK to integrate with Sovant's hosted API.
413
+ - Hosting/redistributing the Sovant backend or any proprietary components is not permitted.
414
+
415
+ ## License
416
+
417
+ MIT -- See [LICENSE](LICENSE) file for details.
@@ -1,14 +1,14 @@
1
- sovant/__init__.py,sha256=u5rAQYbVb4cDn8QvmJB-VusRtSXzQsFH6bAJrBMvvNI,122
1
+ sovant/__init__.py,sha256=5cDlN_M0B40LXBtmhQydiExiBAVPvhKUrgPFz11OVgo,122
2
2
  sovant/base_client.py,sha256=Vmn6OGywGwLbH5cEeflSjVOFwn5iX_YdfTdUq9pWWxA,8778
3
- sovant/client.py,sha256=8VnTPSli1QgRky9PqUb9OAKdbMPTfXlGoUkmAYsFfCw,11804
3
+ sovant/client.py,sha256=ObRKZp1Fz97cYYYx50ZHkEji9Uh9qYc3f0Ob1BLT1xk,13975
4
4
  sovant/exceptions.py,sha256=MQMSgk7ckXnAbe7hPPpbKOnRBHSPxuCY7WSjqfJAvd0,1557
5
5
  sovant/models.py,sha256=avDAITMptDDdDfNH_ed854Q7kF6z_1OzjwJ9Xeft_-8,979
6
6
  sovant/types.py,sha256=gnvdXksJt8LObti7nc6eHSBCB7Pz7SNpS5o_HRTq_kA,6098
7
7
  sovant/resources/__init__.py,sha256=cPFIM7h8duviDdeHudnVEAmv3F89RHQxdH5BCRWFteQ,193
8
8
  sovant/resources/memories.py,sha256=bKKE0uWqFkPa1OEvbK1LrdSD7v6N04RhJ_2VDoPPQBA,11379
9
9
  sovant/resources/threads.py,sha256=mN29xP0JODmZBKyfhpeqJyViUWNVMAx3TlYAW-1ruTs,12558
10
- sovant-1.3.0.dist-info/licenses/LICENSE,sha256=rnNP6-elrMIlQ9jf2aqnHZMyyQ_wvF3y1hTpVUusCWU,1062
11
- sovant-1.3.0.dist-info/METADATA,sha256=6-_NLCFzejStKM-YRnzYNXBLh9WWoNyO4K6cYvr02W4,14201
12
- sovant-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- sovant-1.3.0.dist-info/top_level.txt,sha256=za6eVEsYd_ZQQs8vrmEWNcAR58r1wCDge_jA60e4CvQ,7
14
- sovant-1.3.0.dist-info/RECORD,,
10
+ sovant-1.3.2.dist-info/licenses/LICENSE,sha256=rnNP6-elrMIlQ9jf2aqnHZMyyQ_wvF3y1hTpVUusCWU,1062
11
+ sovant-1.3.2.dist-info/METADATA,sha256=JJ4db5M7GK2oDU7F95-uYwN-DcBxxHGPGmJiKsfv7wA,10604
12
+ sovant-1.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ sovant-1.3.2.dist-info/top_level.txt,sha256=za6eVEsYd_ZQQs8vrmEWNcAR58r1wCDge_jA60e4CvQ,7
14
+ sovant-1.3.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,574 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: sovant
3
- Version: 1.3.0
4
- Summary: Sovant Memory-as-a-Service Python SDK
5
- Author: Sovant
6
- License: MIT
7
- Project-URL: Documentation, https://sovant.ai/docs
8
- Project-URL: Source, https://github.com/hechin91/sovant-ai
9
- Project-URL: Tracker, https://github.com/hechin91/sovant-ai/issues
10
- Requires-Python: >=3.10
11
- Description-Content-Type: text/markdown
12
- License-File: LICENSE
13
- Requires-Dist: httpx>=0.27.0
14
- Requires-Dist: pydantic>=2.8.2
15
- Dynamic: license-file
16
-
17
- # Sovant Python SDK
18
-
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.
21
-
22
- [![PyPI version](https://img.shields.io/pypi/v/sovant.svg)](https://pypi.org/project/sovant/)
23
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
-
25
- ## Installation
26
-
27
- ```bash
28
- pip install sovant
29
- ```
30
-
31
- ## Quick Start
32
-
33
- ```python
34
- from sovant import Sovant
35
-
36
- # Initialize the client
37
- client = Sovant(api_key="sk_live_your_api_key_here", base_url="https://sovant.ai")
38
-
39
- # Create a memory
40
- mem = client.memory.create({
41
- "content": "User prefers dark mode",
42
- "type": "preference",
43
- "tags": ["ui", "settings"]
44
- })
45
-
46
- # Search memories
47
- results = client.memory.search({
48
- "query": "user preferences",
49
- "limit": 10
50
- })
51
-
52
- # Update a memory
53
- updated = client.memory.update(mem["id"], {
54
- "tags": ["ui", "settings", "theme"]
55
- })
56
-
57
- # Delete a memory
58
- client.memory.delete(mem["id"])
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
-
149
- ## Chat in 60 Seconds
150
-
151
- Stream real-time chat responses with memory context:
152
-
153
- ```python
154
- from sovant import Sovant
155
- import sys
156
-
157
- client = Sovant(api_key="sk_live_your_api_key_here", base_url="https://sovant.ai")
158
-
159
- # Create a chat session
160
- session = client.chat.create_session({"title": "Demo"})
161
-
162
- # Stream a response
163
- stream = client.chat.send_message(
164
- session["id"],
165
- "hello",
166
- {
167
- "provider": "openai",
168
- "model": "gpt-4o-mini",
169
- "use_memory": True
170
- },
171
- stream=True
172
- )
173
-
174
- for ev in stream:
175
- if ev["type"] == "delta":
176
- sys.stdout.write(ev.get("data", ""))
177
- elif ev["type"] == "done":
178
- print("\n[done]")
179
-
180
- # Get chat history
181
- messages = client.chat.get_messages(session["id"])
182
- ```
183
-
184
- ## Profile Recall Helpers
185
-
186
- Save and recall user profile facts with canonical patterns:
187
-
188
- ```python
189
- # Extract profile entity from text
190
- fact = client.recall.extract_profile("i'm from kuching")
191
- # -> {"entity": "location", "value": "kuching"} | None
192
-
193
- if fact:
194
- client.recall.save_profile_fact(fact) # canonicalizes and persists
195
-
196
- # Get all profile facts
197
- profile = client.recall.get_profile_facts()
198
- # -> {"name": "...", "age": "...", "location": "...", "preferences": [...]}
199
- ```
200
-
201
- ## Configuration
202
-
203
- ```python
204
- from sovant import Sovant
205
-
206
- client = Sovant(
207
- api_key="sk_live_your_api_key_here", # Required
208
- base_url="https://sovant.ai", # Optional, API endpoint
209
- timeout=30.0, # Optional, request timeout in seconds (default: 30.0)
210
- max_retries=3, # Optional, max retry attempts (default: 3)
211
- debug=False, # Optional, enable debug logging (default: False)
212
- )
213
- ```
214
-
215
- The SDK handles dual authentication automatically, preferring the `x-sovant-api-key` header over `Authorization: Bearer`.
216
-
217
- ## API Reference
218
-
219
- ### Memory Operations
220
-
221
- #### Create Memory
222
-
223
- ```python
224
- memory = client.memory.create({
225
- "content": "Customer contacted support about billing",
226
- "type": "observation", # 'journal' | 'insight' | 'observation' | 'task' | 'preference'
227
- "tags": ["support", "billing"],
228
- "metadata": {"ticket_id": "12345"},
229
- "thread_id": "thread_abc123", # Optional thread association
230
- })
231
- ```
232
-
233
- #### List Memories
234
-
235
- ```python
236
- memories = client.memory.list({
237
- "limit": 20, # Max items per page (default: 20)
238
- "offset": 0, # Pagination offset
239
- "tags": ["billing"], # Filter by tags
240
- "type": "observation", # Filter by type
241
- "is_archived": False, # Filter archived status
242
- })
243
-
244
- print(memories["memories"]) # Array of memories
245
- print(memories["total"]) # Total count
246
- print(memories["has_more"]) # More pages available
247
- ```
248
-
249
- #### Get Memory by ID
250
-
251
- ```python
252
- memory = client.memory.get("mem_123abc")
253
- ```
254
-
255
- #### Update Memory (Partial)
256
-
257
- ```python
258
- updated = client.memory.update("mem_123abc", {
259
- "tags": ["support", "billing", "resolved"],
260
- "metadata": {
261
- **memory.get("metadata", {}),
262
- "resolved": True,
263
- },
264
- "is_archived": True,
265
- })
266
- ```
267
-
268
- #### Replace Memory (Full)
269
-
270
- ```python
271
- replaced = client.memory.put("mem_123abc", {
272
- "content": "Updated content here", # Required for PUT
273
- "type": "observation",
274
- "tags": ["updated"],
275
- })
276
- ```
277
-
278
- #### Delete Memory
279
-
280
- ```python
281
- client.memory.delete("mem_123abc")
282
- ```
283
-
284
- #### Search Memories
285
-
286
- ```python
287
- # Semantic search
288
- semantic_results = client.memory.search({
289
- "query": "customer preferences about notifications",
290
- "limit": 10,
291
- "type": "preference",
292
- })
293
-
294
- # Filter-based search
295
- filter_results = client.memory.search({
296
- "tags": ["settings", "notifications"],
297
- "from_date": "2024-01-01",
298
- "to_date": "2024-12-31",
299
- "limit": 20,
300
- })
301
- ```
302
-
303
- #### Batch Operations
304
-
305
- ```python
306
- batch = client.memory.batch({
307
- "operations": [
308
- {
309
- "op": "create",
310
- "data": {
311
- "content": "First memory",
312
- "type": "journal",
313
- },
314
- },
315
- {
316
- "op": "update",
317
- "id": "mem_123abc",
318
- "data": {
319
- "tags": ["updated"],
320
- },
321
- },
322
- {
323
- "op": "delete",
324
- "id": "mem_456def",
325
- },
326
- ],
327
- })
328
-
329
- print(batch["results"]) # Individual operation results
330
- print(batch["summary"]) # Summary statistics
331
- ```
332
-
333
- ### Thread Management
334
-
335
- Associate memories with conversation threads:
336
-
337
- ```python
338
- # Create a thread
339
- thread = client.threads.create({
340
- "title": "Customer Support Session",
341
- "metadata": {"user_id": "user_123"}
342
- })
343
-
344
- # List threads
345
- threads = client.threads.list({
346
- "limit": 10,
347
- "offset": 0
348
- })
349
-
350
- # Get thread by ID
351
- thread = client.threads.get("thread_abc123")
352
-
353
- # Update thread
354
- updated_thread = client.threads.update("thread_abc123", {
355
- "title": "Resolved: Billing Issue",
356
- "metadata": {"status": "resolved"}
357
- })
358
-
359
- # Delete thread
360
- client.threads.delete("thread_abc123")
361
-
362
- # Link memory to thread
363
- client.threads.link_memory("thread_abc123", "mem_123abc")
364
-
365
- # Create memories within a thread
366
- memory1 = client.memory.create({
367
- "content": "User asked about pricing",
368
- "type": "observation",
369
- "thread_id": "thread_abc123",
370
- })
371
-
372
- memory2 = client.memory.create({
373
- "content": "User selected enterprise plan",
374
- "type": "observation",
375
- "thread_id": "thread_abc123",
376
- })
377
-
378
- # List memories in a thread
379
- thread_memories = client.memory.list({
380
- "thread_id": "thread_abc123",
381
- })
382
- ```
383
-
384
- ### API Key Management
385
-
386
- Manage API keys programmatically:
387
-
388
- ```python
389
- # List all API keys
390
- keys = client.keys.list()
391
- print(keys) # Array of key objects
392
-
393
- # Create a new API key
394
- new_key = client.keys.create({"name": "CI key"})
395
- print(new_key["key"]) # The actual secret key (only shown once!)
396
-
397
- # Update key metadata
398
- client.keys.update(new_key["id"], {"name": "Production key"})
399
-
400
- # Revoke a key
401
- client.keys.revoke(new_key["id"])
402
- ```
403
-
404
- ## Memory Types
405
-
406
- - **journal** - Chronological entries and logs
407
- - **insight** - Derived patterns and conclusions
408
- - **observation** - Factual, observed information
409
- - **task** - Action items and todos
410
- - **preference** - User preferences and settings
411
-
412
- ## Error Handling
413
-
414
- The SDK provides typed errors for better error handling:
415
-
416
- ```python
417
- from sovant import Sovant, SovantError, AuthError, RateLimitError, NetworkError, TimeoutError
418
-
419
- try:
420
- memory = client.memory.get("invalid_id")
421
- except AuthError as e:
422
- print(f"Authentication failed: {e}")
423
- # Handle authentication error
424
- except RateLimitError as e:
425
- print(f"Rate limit exceeded: {e}")
426
- print(f"Retry after: {e.retry_after}")
427
- # Handle rate limiting
428
- except NetworkError as e:
429
- print(f"Network error: {e}")
430
- # Handle network issues
431
- except TimeoutError as e:
432
- print(f"Request timed out: {e}")
433
- # Handle timeout
434
- except SovantError as e:
435
- print(f"API Error: {e}")
436
- print(f"Status: {e.status}")
437
- print(f"Request ID: {e.request_id}")
438
-
439
- if e.status == 404:
440
- # Handle not found
441
- pass
442
- elif e.status == 400:
443
- # Handle bad request
444
- pass
445
- ```
446
-
447
- ## Advanced Features
448
-
449
- ### Retry Configuration
450
-
451
- The SDK automatically retries failed requests with exponential backoff:
452
-
453
- ```python
454
- client = Sovant(
455
- api_key="sk_live_...",
456
- max_retries=5, # Increase retry attempts
457
- timeout=60.0, # Increase timeout for slow connections
458
- )
459
- ```
460
-
461
- ### Debug Mode
462
-
463
- Enable debug logging to see detailed request/response information:
464
-
465
- ```python
466
- client = Sovant(
467
- api_key="sk_live_...",
468
- debug=True, # Enable debug output
469
- )
470
- ```
471
-
472
- ### Custom Base URL
473
-
474
- Connect to different environments:
475
-
476
- ```python
477
- client = Sovant(
478
- api_key="sk_live_...",
479
- base_url="https://staging.sovant.ai",
480
- )
481
- ```
482
-
483
- ## Best Practices
484
-
485
- 1. **Use appropriate memory types** - Choose the correct type for your use case
486
- 2. **Add meaningful tags** - Tags improve searchability and organization
487
- 3. **Use threads** - Group related memories together
488
- 4. **Handle errors gracefully** - Implement proper error handling
489
- 5. **Batch operations** - Use batch API for multiple operations
490
- 6. **Archive don't delete** - Consider archiving instead of deleting
491
-
492
- ## Examples
493
-
494
- ### Customer Support Integration
495
-
496
- ```python
497
- # Track customer interaction
498
- interaction = client.memory.create({
499
- "content": "Customer reported slow dashboard loading",
500
- "type": "observation",
501
- "thread_id": f"ticket_{ticket_id}",
502
- "tags": ["support", "performance", "dashboard"],
503
- "metadata": {
504
- "ticket_id": ticket_id,
505
- "customer_id": customer_id,
506
- "priority": "high",
507
- },
508
- })
509
-
510
- # Record resolution
511
- resolution = client.memory.create({
512
- "content": "Resolved by clearing cache and upgrading plan",
513
- "type": "insight",
514
- "thread_id": f"ticket_{ticket_id}",
515
- "tags": ["support", "resolved"],
516
- "metadata": {
517
- "ticket_id": ticket_id,
518
- "resolution_time": "2h",
519
- },
520
- })
521
- ```
522
-
523
- ### User Preference Tracking
524
-
525
- ```python
526
- # Store preference
527
- preference = client.memory.create({
528
- "content": "User prefers email notifications over SMS",
529
- "type": "preference",
530
- "tags": ["notifications", "email", "settings"],
531
- "metadata": {
532
- "user_id": user_id,
533
- "setting": "notification_channel",
534
- "value": "email",
535
- },
536
- })
537
-
538
- # Query preferences
539
- preferences = client.memory.search({
540
- "query": "notification preferences",
541
- "type": "preference",
542
- "tags": ["notifications"],
543
- })
544
- ```
545
-
546
- ## Rate Limiting
547
-
548
- The API implements rate limiting. The SDK automatically handles rate limit responses with retries. Rate limit headers are included in responses:
549
-
550
- - `X-RateLimit-Limit` - Request limit per window
551
- - `X-RateLimit-Remaining` - Remaining requests
552
- - `X-RateLimit-Reset` - Reset timestamp
553
-
554
- ## Support
555
-
556
- - Documentation: [https://sovant.ai/docs](https://sovant.ai/docs)
557
- - API/Auth docs: [https://sovant.ai/docs/security/auth](https://sovant.ai/docs/security/auth)
558
- - Issues: [GitHub Issues](https://github.com/sovant-ai/python-sdk/issues)
559
- - Support: support@sovant.ai
560
-
561
- ## Changelog
562
-
563
- See [CHANGELOG.md](./CHANGELOG.md) for a detailed history of changes.
564
-
565
- ## License & Use
566
-
567
- - This SDK is MIT-licensed for integration convenience.
568
- - The Sovant API and platform are proprietary to Sovant Technologies Sdn. Bhd.
569
- - You may use this SDK to integrate with Sovant's hosted API.
570
- - Hosting/redistributing the Sovant backend or any proprietary components is not permitted.
571
-
572
- ## License
573
-
574
- MIT - See [LICENSE](LICENSE) file for details.