sovant 1.3.0__py3-none-any.whl → 1.3.1__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 +1 -1
- sovant-1.3.1.dist-info/METADATA +381 -0
- {sovant-1.3.0.dist-info → sovant-1.3.1.dist-info}/RECORD +6 -6
- {sovant-1.3.0.dist-info → sovant-1.3.1.dist-info}/WHEEL +1 -1
- sovant-1.3.0.dist-info/METADATA +0 -574
- {sovant-1.3.0.dist-info → sovant-1.3.1.dist-info}/licenses/LICENSE +0 -0
- {sovant-1.3.0.dist-info → sovant-1.3.1.dist-info}/top_level.txt +0 -0
sovant/__init__.py
CHANGED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sovant
|
|
3
|
+
Version: 1.3.1
|
|
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
|
+
[](https://pypi.org/project/sovant/)
|
|
23
|
+
[](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
|
+
### Thread Management
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
# Create a thread
|
|
258
|
+
thread = client.threads_create(
|
|
259
|
+
title="Customer Support Session",
|
|
260
|
+
metadata={"user_id": "user_123"},
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# List threads
|
|
264
|
+
threads = client.threads_list(limit=10, offset=0)
|
|
265
|
+
|
|
266
|
+
# Get thread by ID (with memories)
|
|
267
|
+
thread = client.threads_get("thread_abc123", include_memories=True)
|
|
268
|
+
|
|
269
|
+
# Update thread
|
|
270
|
+
updated = client.threads_update(
|
|
271
|
+
"thread_abc123",
|
|
272
|
+
title="Resolved: Billing Issue",
|
|
273
|
+
status="completed",
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Delete thread
|
|
277
|
+
client.threads_delete("thread_abc123")
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Memory Types
|
|
281
|
+
|
|
282
|
+
- **journal** -- Chronological entries and logs
|
|
283
|
+
- **insight** -- Derived patterns and conclusions
|
|
284
|
+
- **observation** -- Factual, observed information
|
|
285
|
+
- **task** -- Action items and todos
|
|
286
|
+
- **preference** -- User preferences and settings
|
|
287
|
+
|
|
288
|
+
## Error Handling
|
|
289
|
+
|
|
290
|
+
The SDK raises `SovantError` for all API errors:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from sovant import Sovant, SovantError
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
memory = client.memory_get("invalid_id")
|
|
297
|
+
except SovantError as e:
|
|
298
|
+
print(f"Error: {e}")
|
|
299
|
+
print(f"Code: {e.code}") # e.g. "NOT_FOUND", "HTTP_401"
|
|
300
|
+
print(f"Status: {e.status}") # e.g. 404, 401
|
|
301
|
+
|
|
302
|
+
if e.status == 404:
|
|
303
|
+
print("Memory not found")
|
|
304
|
+
elif e.status == 401:
|
|
305
|
+
print("Invalid API key")
|
|
306
|
+
elif e.status == 429:
|
|
307
|
+
print("Rate limited -- SDK retries automatically")
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The SDK automatically retries on rate limit (429) and server errors (5xx) with exponential backoff.
|
|
311
|
+
|
|
312
|
+
## Examples
|
|
313
|
+
|
|
314
|
+
### Customer Support Integration
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from sovant import MemoryCreate
|
|
318
|
+
|
|
319
|
+
# Track customer interaction
|
|
320
|
+
interaction = client.memory_create(MemoryCreate(
|
|
321
|
+
data="Customer reported slow dashboard loading",
|
|
322
|
+
type="observation",
|
|
323
|
+
thread_id=f"ticket_{ticket_id}",
|
|
324
|
+
tags=["support", "performance", "dashboard"],
|
|
325
|
+
metadata={
|
|
326
|
+
"ticket_id": ticket_id,
|
|
327
|
+
"priority": "high",
|
|
328
|
+
},
|
|
329
|
+
))
|
|
330
|
+
|
|
331
|
+
# Record resolution
|
|
332
|
+
resolution = client.memory_create(MemoryCreate(
|
|
333
|
+
data="Resolved by clearing cache and upgrading plan",
|
|
334
|
+
type="insight",
|
|
335
|
+
thread_id=f"ticket_{ticket_id}",
|
|
336
|
+
tags=["support", "resolved"],
|
|
337
|
+
))
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### User Preference Tracking
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from sovant import MemoryCreate, SearchQuery
|
|
344
|
+
|
|
345
|
+
# Store preference
|
|
346
|
+
client.memory_create(MemoryCreate(
|
|
347
|
+
data="User prefers email notifications over SMS",
|
|
348
|
+
type="preference",
|
|
349
|
+
tags=["notifications", "email"],
|
|
350
|
+
))
|
|
351
|
+
|
|
352
|
+
# Query preferences
|
|
353
|
+
preferences = client.memory_search(SearchQuery(
|
|
354
|
+
query="notification preferences",
|
|
355
|
+
type="preference",
|
|
356
|
+
))
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Rate Limiting
|
|
360
|
+
|
|
361
|
+
The API enforces 60 requests per minute. The SDK automatically retries rate-limited requests with exponential backoff. Rate limit headers are included in responses:
|
|
362
|
+
|
|
363
|
+
- `X-RateLimit-Limit` -- Request limit per window
|
|
364
|
+
- `X-RateLimit-Remaining` -- Remaining requests
|
|
365
|
+
- `X-RateLimit-Reset` -- Reset timestamp
|
|
366
|
+
|
|
367
|
+
## Support
|
|
368
|
+
|
|
369
|
+
- Documentation: [https://sovant.ai/docs](https://sovant.ai/docs)
|
|
370
|
+
- Issues: [GitHub Issues](https://github.com/hechin91/sovant-ai/issues)
|
|
371
|
+
|
|
372
|
+
## License & Use
|
|
373
|
+
|
|
374
|
+
- This SDK is MIT-licensed for integration convenience.
|
|
375
|
+
- The Sovant API and platform are proprietary to Sovant Technologies Sdn. Bhd.
|
|
376
|
+
- You may use this SDK to integrate with Sovant's hosted API.
|
|
377
|
+
- Hosting/redistributing the Sovant backend or any proprietary components is not permitted.
|
|
378
|
+
|
|
379
|
+
## License
|
|
380
|
+
|
|
381
|
+
MIT -- See [LICENSE](LICENSE) file for details.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sovant/__init__.py,sha256=
|
|
1
|
+
sovant/__init__.py,sha256=t0XgMU44um_gJBNGkg8QnaEC1SXsIh56IF2TrdDgbuY,122
|
|
2
2
|
sovant/base_client.py,sha256=Vmn6OGywGwLbH5cEeflSjVOFwn5iX_YdfTdUq9pWWxA,8778
|
|
3
3
|
sovant/client.py,sha256=8VnTPSli1QgRky9PqUb9OAKdbMPTfXlGoUkmAYsFfCw,11804
|
|
4
4
|
sovant/exceptions.py,sha256=MQMSgk7ckXnAbe7hPPpbKOnRBHSPxuCY7WSjqfJAvd0,1557
|
|
@@ -7,8 +7,8 @@ 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.
|
|
11
|
-
sovant-1.3.
|
|
12
|
-
sovant-1.3.
|
|
13
|
-
sovant-1.3.
|
|
14
|
-
sovant-1.3.
|
|
10
|
+
sovant-1.3.1.dist-info/licenses/LICENSE,sha256=rnNP6-elrMIlQ9jf2aqnHZMyyQ_wvF3y1hTpVUusCWU,1062
|
|
11
|
+
sovant-1.3.1.dist-info/METADATA,sha256=ej271WYl3oSvAlmWRCVIjr_ebFSkgzw4-C3NVCOm01k,9515
|
|
12
|
+
sovant-1.3.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
+
sovant-1.3.1.dist-info/top_level.txt,sha256=za6eVEsYd_ZQQs8vrmEWNcAR58r1wCDge_jA60e4CvQ,7
|
|
14
|
+
sovant-1.3.1.dist-info/RECORD,,
|
sovant-1.3.0.dist-info/METADATA
DELETED
|
@@ -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
|
-
[](https://pypi.org/project/sovant/)
|
|
23
|
-
[](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.
|
|
File without changes
|
|
File without changes
|