sovant 1.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.
- sovant-1.1.0/LICENSE +21 -0
- sovant-1.1.0/MANIFEST.in +7 -0
- sovant-1.1.0/PKG-INFO +485 -0
- sovant-1.1.0/README.md +469 -0
- sovant-1.1.0/pyproject.toml +18 -0
- sovant-1.1.0/setup.cfg +4 -0
- sovant-1.1.0/src/sovant/__init__.py +4 -0
- sovant-1.1.0/src/sovant/base_client.py +256 -0
- sovant-1.1.0/src/sovant/client.py +202 -0
- sovant-1.1.0/src/sovant/exceptions.py +58 -0
- sovant-1.1.0/src/sovant/models.py +30 -0
- sovant-1.1.0/src/sovant/resources/__init__.py +6 -0
- sovant-1.1.0/src/sovant/resources/memories.py +317 -0
- sovant-1.1.0/src/sovant/resources/threads.py +362 -0
- sovant-1.1.0/src/sovant/types.py +224 -0
- sovant-1.1.0/src/sovant.egg-info/PKG-INFO +485 -0
- sovant-1.1.0/src/sovant.egg-info/SOURCES.txt +18 -0
- sovant-1.1.0/src/sovant.egg-info/dependency_links.txt +1 -0
- sovant-1.1.0/src/sovant.egg-info/requires.txt +2 -0
- sovant-1.1.0/src/sovant.egg-info/top_level.txt +1 -0
sovant-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sovant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sovant-1.1.0/MANIFEST.in
ADDED
sovant-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sovant
|
|
3
|
+
Version: 1.1.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 Memory-as-a-Service: a durable, queryable memory layer for AI apps with cross-model recall, hybrid (semantic + deterministic) retrieval, and simple SDKs.
|
|
20
|
+
|
|
21
|
+
[](https://pypi.org/project/sovant/)
|
|
22
|
+
[](https://opensource.org/licenses/MIT)
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install sovant
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from sovant import Sovant
|
|
34
|
+
|
|
35
|
+
# Initialize the client
|
|
36
|
+
client = Sovant(api_key="sk_live_your_api_key_here", base_url="https://sovant.ai")
|
|
37
|
+
|
|
38
|
+
# Create a memory
|
|
39
|
+
mem = client.memory.create({
|
|
40
|
+
"content": "User prefers dark mode",
|
|
41
|
+
"type": "preference",
|
|
42
|
+
"tags": ["ui", "settings"]
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
# Search memories
|
|
46
|
+
results = client.memory.search({
|
|
47
|
+
"query": "user preferences",
|
|
48
|
+
"limit": 10
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
# Update a memory
|
|
52
|
+
updated = client.memory.update(mem["id"], {
|
|
53
|
+
"tags": ["ui", "settings", "theme"]
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
# Delete a memory
|
|
57
|
+
client.memory.delete(mem["id"])
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Chat in 60 Seconds
|
|
61
|
+
|
|
62
|
+
Stream real-time chat responses with memory context:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from sovant import Sovant
|
|
66
|
+
import sys
|
|
67
|
+
|
|
68
|
+
client = Sovant(api_key="sk_live_your_api_key_here", base_url="https://sovant.ai")
|
|
69
|
+
|
|
70
|
+
# Create a chat session
|
|
71
|
+
session = client.chat.create_session({"title": "Demo"})
|
|
72
|
+
|
|
73
|
+
# Stream a response
|
|
74
|
+
stream = client.chat.send_message(
|
|
75
|
+
session["id"],
|
|
76
|
+
"hello",
|
|
77
|
+
{
|
|
78
|
+
"provider": "openai",
|
|
79
|
+
"model": "gpt-4o-mini",
|
|
80
|
+
"use_memory": True
|
|
81
|
+
},
|
|
82
|
+
stream=True
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
for ev in stream:
|
|
86
|
+
if ev["type"] == "delta":
|
|
87
|
+
sys.stdout.write(ev.get("data", ""))
|
|
88
|
+
elif ev["type"] == "done":
|
|
89
|
+
print("\n[done]")
|
|
90
|
+
|
|
91
|
+
# Get chat history
|
|
92
|
+
messages = client.chat.get_messages(session["id"])
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Profile Recall Helpers
|
|
96
|
+
|
|
97
|
+
Save and recall user profile facts with canonical patterns:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
# Extract profile entity from text
|
|
101
|
+
fact = client.recall.extract_profile("i'm from kuching")
|
|
102
|
+
# -> {"entity": "location", "value": "kuching"} | None
|
|
103
|
+
|
|
104
|
+
if fact:
|
|
105
|
+
client.recall.save_profile_fact(fact) # canonicalizes and persists
|
|
106
|
+
|
|
107
|
+
# Get all profile facts
|
|
108
|
+
profile = client.recall.get_profile_facts()
|
|
109
|
+
# -> {"name": "...", "age": "...", "location": "...", "preferences": [...]}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Configuration
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from sovant import Sovant
|
|
116
|
+
|
|
117
|
+
client = Sovant(
|
|
118
|
+
api_key="sk_live_your_api_key_here", # Required
|
|
119
|
+
base_url="https://sovant.ai", # Optional, API endpoint
|
|
120
|
+
timeout=30.0, # Optional, request timeout in seconds (default: 30.0)
|
|
121
|
+
max_retries=3, # Optional, max retry attempts (default: 3)
|
|
122
|
+
debug=False, # Optional, enable debug logging (default: False)
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The SDK handles dual authentication automatically, preferring the `x-sovant-api-key` header over `Authorization: Bearer`.
|
|
127
|
+
|
|
128
|
+
## API Reference
|
|
129
|
+
|
|
130
|
+
### Memory Operations
|
|
131
|
+
|
|
132
|
+
#### Create Memory
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
memory = client.memory.create({
|
|
136
|
+
"content": "Customer contacted support about billing",
|
|
137
|
+
"type": "observation", # 'journal' | 'insight' | 'observation' | 'task' | 'preference'
|
|
138
|
+
"tags": ["support", "billing"],
|
|
139
|
+
"metadata": {"ticket_id": "12345"},
|
|
140
|
+
"thread_id": "thread_abc123", # Optional thread association
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### List Memories
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
memories = client.memory.list({
|
|
148
|
+
"limit": 20, # Max items per page (default: 20)
|
|
149
|
+
"offset": 0, # Pagination offset
|
|
150
|
+
"tags": ["billing"], # Filter by tags
|
|
151
|
+
"type": "observation", # Filter by type
|
|
152
|
+
"is_archived": False, # Filter archived status
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
print(memories["memories"]) # Array of memories
|
|
156
|
+
print(memories["total"]) # Total count
|
|
157
|
+
print(memories["has_more"]) # More pages available
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Get Memory by ID
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
memory = client.memory.get("mem_123abc")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Update Memory (Partial)
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
updated = client.memory.update("mem_123abc", {
|
|
170
|
+
"tags": ["support", "billing", "resolved"],
|
|
171
|
+
"metadata": {
|
|
172
|
+
**memory.get("metadata", {}),
|
|
173
|
+
"resolved": True,
|
|
174
|
+
},
|
|
175
|
+
"is_archived": True,
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Replace Memory (Full)
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
replaced = client.memory.put("mem_123abc", {
|
|
183
|
+
"content": "Updated content here", # Required for PUT
|
|
184
|
+
"type": "observation",
|
|
185
|
+
"tags": ["updated"],
|
|
186
|
+
})
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Delete Memory
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
client.memory.delete("mem_123abc")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### Search Memories
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
# Semantic search
|
|
199
|
+
semantic_results = client.memory.search({
|
|
200
|
+
"query": "customer preferences about notifications",
|
|
201
|
+
"limit": 10,
|
|
202
|
+
"type": "preference",
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
# Filter-based search
|
|
206
|
+
filter_results = client.memory.search({
|
|
207
|
+
"tags": ["settings", "notifications"],
|
|
208
|
+
"from_date": "2024-01-01",
|
|
209
|
+
"to_date": "2024-12-31",
|
|
210
|
+
"limit": 20,
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Batch Operations
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
batch = client.memory.batch({
|
|
218
|
+
"operations": [
|
|
219
|
+
{
|
|
220
|
+
"op": "create",
|
|
221
|
+
"data": {
|
|
222
|
+
"content": "First memory",
|
|
223
|
+
"type": "journal",
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"op": "update",
|
|
228
|
+
"id": "mem_123abc",
|
|
229
|
+
"data": {
|
|
230
|
+
"tags": ["updated"],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"op": "delete",
|
|
235
|
+
"id": "mem_456def",
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
print(batch["results"]) # Individual operation results
|
|
241
|
+
print(batch["summary"]) # Summary statistics
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Thread Management
|
|
245
|
+
|
|
246
|
+
Associate memories with conversation threads:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
# Create a thread
|
|
250
|
+
thread = client.threads.create({
|
|
251
|
+
"title": "Customer Support Session",
|
|
252
|
+
"metadata": {"user_id": "user_123"}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
# List threads
|
|
256
|
+
threads = client.threads.list({
|
|
257
|
+
"limit": 10,
|
|
258
|
+
"offset": 0
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
# Get thread by ID
|
|
262
|
+
thread = client.threads.get("thread_abc123")
|
|
263
|
+
|
|
264
|
+
# Update thread
|
|
265
|
+
updated_thread = client.threads.update("thread_abc123", {
|
|
266
|
+
"title": "Resolved: Billing Issue",
|
|
267
|
+
"metadata": {"status": "resolved"}
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
# Delete thread
|
|
271
|
+
client.threads.delete("thread_abc123")
|
|
272
|
+
|
|
273
|
+
# Link memory to thread
|
|
274
|
+
client.threads.link_memory("thread_abc123", "mem_123abc")
|
|
275
|
+
|
|
276
|
+
# Create memories within a thread
|
|
277
|
+
memory1 = client.memory.create({
|
|
278
|
+
"content": "User asked about pricing",
|
|
279
|
+
"type": "observation",
|
|
280
|
+
"thread_id": "thread_abc123",
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
memory2 = client.memory.create({
|
|
284
|
+
"content": "User selected enterprise plan",
|
|
285
|
+
"type": "observation",
|
|
286
|
+
"thread_id": "thread_abc123",
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
# List memories in a thread
|
|
290
|
+
thread_memories = client.memory.list({
|
|
291
|
+
"thread_id": "thread_abc123",
|
|
292
|
+
})
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### API Key Management
|
|
296
|
+
|
|
297
|
+
Manage API keys programmatically:
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
# List all API keys
|
|
301
|
+
keys = client.keys.list()
|
|
302
|
+
print(keys) # Array of key objects
|
|
303
|
+
|
|
304
|
+
# Create a new API key
|
|
305
|
+
new_key = client.keys.create({"name": "CI key"})
|
|
306
|
+
print(new_key["key"]) # The actual secret key (only shown once!)
|
|
307
|
+
|
|
308
|
+
# Update key metadata
|
|
309
|
+
client.keys.update(new_key["id"], {"name": "Production key"})
|
|
310
|
+
|
|
311
|
+
# Revoke a key
|
|
312
|
+
client.keys.revoke(new_key["id"])
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Memory Types
|
|
316
|
+
|
|
317
|
+
- **journal** - Chronological entries and logs
|
|
318
|
+
- **insight** - Derived patterns and conclusions
|
|
319
|
+
- **observation** - Factual, observed information
|
|
320
|
+
- **task** - Action items and todos
|
|
321
|
+
- **preference** - User preferences and settings
|
|
322
|
+
|
|
323
|
+
## Error Handling
|
|
324
|
+
|
|
325
|
+
The SDK provides typed errors for better error handling:
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
from sovant import Sovant, SovantError, AuthError, RateLimitError, NetworkError, TimeoutError
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
memory = client.memory.get("invalid_id")
|
|
332
|
+
except AuthError as e:
|
|
333
|
+
print(f"Authentication failed: {e}")
|
|
334
|
+
# Handle authentication error
|
|
335
|
+
except RateLimitError as e:
|
|
336
|
+
print(f"Rate limit exceeded: {e}")
|
|
337
|
+
print(f"Retry after: {e.retry_after}")
|
|
338
|
+
# Handle rate limiting
|
|
339
|
+
except NetworkError as e:
|
|
340
|
+
print(f"Network error: {e}")
|
|
341
|
+
# Handle network issues
|
|
342
|
+
except TimeoutError as e:
|
|
343
|
+
print(f"Request timed out: {e}")
|
|
344
|
+
# Handle timeout
|
|
345
|
+
except SovantError as e:
|
|
346
|
+
print(f"API Error: {e}")
|
|
347
|
+
print(f"Status: {e.status}")
|
|
348
|
+
print(f"Request ID: {e.request_id}")
|
|
349
|
+
|
|
350
|
+
if e.status == 404:
|
|
351
|
+
# Handle not found
|
|
352
|
+
pass
|
|
353
|
+
elif e.status == 400:
|
|
354
|
+
# Handle bad request
|
|
355
|
+
pass
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Advanced Features
|
|
359
|
+
|
|
360
|
+
### Retry Configuration
|
|
361
|
+
|
|
362
|
+
The SDK automatically retries failed requests with exponential backoff:
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
client = Sovant(
|
|
366
|
+
api_key="sk_live_...",
|
|
367
|
+
max_retries=5, # Increase retry attempts
|
|
368
|
+
timeout=60.0, # Increase timeout for slow connections
|
|
369
|
+
)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Debug Mode
|
|
373
|
+
|
|
374
|
+
Enable debug logging to see detailed request/response information:
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
client = Sovant(
|
|
378
|
+
api_key="sk_live_...",
|
|
379
|
+
debug=True, # Enable debug output
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Custom Base URL
|
|
384
|
+
|
|
385
|
+
Connect to different environments:
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
client = Sovant(
|
|
389
|
+
api_key="sk_live_...",
|
|
390
|
+
base_url="https://staging.sovant.ai",
|
|
391
|
+
)
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Best Practices
|
|
395
|
+
|
|
396
|
+
1. **Use appropriate memory types** - Choose the correct type for your use case
|
|
397
|
+
2. **Add meaningful tags** - Tags improve searchability and organization
|
|
398
|
+
3. **Use threads** - Group related memories together
|
|
399
|
+
4. **Handle errors gracefully** - Implement proper error handling
|
|
400
|
+
5. **Batch operations** - Use batch API for multiple operations
|
|
401
|
+
6. **Archive don't delete** - Consider archiving instead of deleting
|
|
402
|
+
|
|
403
|
+
## Examples
|
|
404
|
+
|
|
405
|
+
### Customer Support Integration
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
# Track customer interaction
|
|
409
|
+
interaction = client.memory.create({
|
|
410
|
+
"content": "Customer reported slow dashboard loading",
|
|
411
|
+
"type": "observation",
|
|
412
|
+
"thread_id": f"ticket_{ticket_id}",
|
|
413
|
+
"tags": ["support", "performance", "dashboard"],
|
|
414
|
+
"metadata": {
|
|
415
|
+
"ticket_id": ticket_id,
|
|
416
|
+
"customer_id": customer_id,
|
|
417
|
+
"priority": "high",
|
|
418
|
+
},
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
# Record resolution
|
|
422
|
+
resolution = client.memory.create({
|
|
423
|
+
"content": "Resolved by clearing cache and upgrading plan",
|
|
424
|
+
"type": "insight",
|
|
425
|
+
"thread_id": f"ticket_{ticket_id}",
|
|
426
|
+
"tags": ["support", "resolved"],
|
|
427
|
+
"metadata": {
|
|
428
|
+
"ticket_id": ticket_id,
|
|
429
|
+
"resolution_time": "2h",
|
|
430
|
+
},
|
|
431
|
+
})
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### User Preference Tracking
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
# Store preference
|
|
438
|
+
preference = client.memory.create({
|
|
439
|
+
"content": "User prefers email notifications over SMS",
|
|
440
|
+
"type": "preference",
|
|
441
|
+
"tags": ["notifications", "email", "settings"],
|
|
442
|
+
"metadata": {
|
|
443
|
+
"user_id": user_id,
|
|
444
|
+
"setting": "notification_channel",
|
|
445
|
+
"value": "email",
|
|
446
|
+
},
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
# Query preferences
|
|
450
|
+
preferences = client.memory.search({
|
|
451
|
+
"query": "notification preferences",
|
|
452
|
+
"type": "preference",
|
|
453
|
+
"tags": ["notifications"],
|
|
454
|
+
})
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Rate Limiting
|
|
458
|
+
|
|
459
|
+
The API implements rate limiting. The SDK automatically handles rate limit responses with retries. Rate limit headers are included in responses:
|
|
460
|
+
|
|
461
|
+
- `X-RateLimit-Limit` - Request limit per window
|
|
462
|
+
- `X-RateLimit-Remaining` - Remaining requests
|
|
463
|
+
- `X-RateLimit-Reset` - Reset timestamp
|
|
464
|
+
|
|
465
|
+
## Support
|
|
466
|
+
|
|
467
|
+
- Documentation: [https://sovant.ai/docs](https://sovant.ai/docs)
|
|
468
|
+
- API/Auth docs: [https://sovant.ai/docs/security/auth](https://sovant.ai/docs/security/auth)
|
|
469
|
+
- Issues: [GitHub Issues](https://github.com/sovant-ai/python-sdk/issues)
|
|
470
|
+
- Support: support@sovant.ai
|
|
471
|
+
|
|
472
|
+
## Changelog
|
|
473
|
+
|
|
474
|
+
See [CHANGELOG.md](./CHANGELOG.md) for a detailed history of changes.
|
|
475
|
+
|
|
476
|
+
## License & Use
|
|
477
|
+
|
|
478
|
+
- This SDK is MIT-licensed for integration convenience.
|
|
479
|
+
- The Sovant API and platform are proprietary to Sovant Technologies Sdn. Bhd.
|
|
480
|
+
- You may use this SDK to integrate with Sovant's hosted API.
|
|
481
|
+
- Hosting/redistributing the Sovant backend or any proprietary components is not permitted.
|
|
482
|
+
|
|
483
|
+
## License
|
|
484
|
+
|
|
485
|
+
MIT - See [LICENSE](LICENSE) file for details.
|