sonzai 1.0.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.
- sonzai-1.0.0/.gitignore +16 -0
- sonzai-1.0.0/LICENSE +21 -0
- sonzai-1.0.0/PKG-INFO +479 -0
- sonzai-1.0.0/README.md +448 -0
- sonzai-1.0.0/pyproject.toml +62 -0
- sonzai-1.0.0/src/sonzai/__init__.py +281 -0
- sonzai-1.0.0/src/sonzai/_client.py +171 -0
- sonzai-1.0.0/src/sonzai/_exceptions.py +44 -0
- sonzai-1.0.0/src/sonzai/_http.py +275 -0
- sonzai-1.0.0/src/sonzai/py.typed +0 -0
- sonzai-1.0.0/src/sonzai/resources/__init__.py +26 -0
- sonzai-1.0.0/src/sonzai/resources/agents.py +1927 -0
- sonzai-1.0.0/src/sonzai/resources/custom_states.py +326 -0
- sonzai-1.0.0/src/sonzai/resources/eval_runs.py +95 -0
- sonzai-1.0.0/src/sonzai/resources/eval_templates.py +186 -0
- sonzai-1.0.0/src/sonzai/resources/generation.py +383 -0
- sonzai-1.0.0/src/sonzai/resources/instances.py +147 -0
- sonzai-1.0.0/src/sonzai/resources/inventory.py +347 -0
- sonzai-1.0.0/src/sonzai/resources/knowledge.py +662 -0
- sonzai-1.0.0/src/sonzai/resources/memory.py +314 -0
- sonzai-1.0.0/src/sonzai/resources/notifications.py +99 -0
- sonzai-1.0.0/src/sonzai/resources/personality.py +197 -0
- sonzai-1.0.0/src/sonzai/resources/priming.py +208 -0
- sonzai-1.0.0/src/sonzai/resources/sessions.py +140 -0
- sonzai-1.0.0/src/sonzai/resources/voice.py +689 -0
- sonzai-1.0.0/src/sonzai/resources/webhooks.py +119 -0
- sonzai-1.0.0/src/sonzai/types.py +1382 -0
- sonzai-1.0.0/tests/__init__.py +0 -0
- sonzai-1.0.0/tests/test_client.py +383 -0
- sonzai-1.0.0/tests/test_types.py +131 -0
sonzai-1.0.0/.gitignore
ADDED
sonzai-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sonzai Labs
|
|
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.
|
sonzai-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sonzai
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for the Sonzai Character Engine API
|
|
5
|
+
Project-URL: Homepage, https://github.com/sonz-ai/sonzai-python
|
|
6
|
+
Project-URL: Documentation, https://github.com/sonz-ai/sonzai-python#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/sonz-ai/sonzai-python
|
|
8
|
+
Project-URL: Issues, https://github.com/sonz-ai/sonzai-python/issues
|
|
9
|
+
Author-email: Sonzai Labs <eng@sonz.ai>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,ai,character-engine,llm,sonzai
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Sonzai Python SDK
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/sonzai/)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://www.python.org/downloads/)
|
|
37
|
+
|
|
38
|
+
The official Python SDK for the [Sonzai Character Engine API](https://sonz.ai). Build AI characters with persistent memory, evolving personality, and proactive behaviors.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install sonzai
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from sonzai import Sonzai
|
|
50
|
+
|
|
51
|
+
client = Sonzai(api_key="your-api-key")
|
|
52
|
+
|
|
53
|
+
# Chat with an agent
|
|
54
|
+
response = client.agents.chat(
|
|
55
|
+
"your-agent-id",
|
|
56
|
+
messages=[{"role": "user", "content": "Hello! What's your favorite hobby?"}],
|
|
57
|
+
user_id="user-123",
|
|
58
|
+
)
|
|
59
|
+
print(response.content)
|
|
60
|
+
|
|
61
|
+
client.close()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Authentication
|
|
65
|
+
|
|
66
|
+
Get your API key from the [Sonzai Dashboard](https://platform.sonz.ai) under **Projects > API Keys**.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Pass directly
|
|
70
|
+
client = Sonzai(api_key="sk-...")
|
|
71
|
+
|
|
72
|
+
# Or set the environment variable
|
|
73
|
+
# export SONZAI_API_KEY=sk-...
|
|
74
|
+
client = Sonzai()
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
### Chat (Streaming)
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
for event in client.agents.chat(
|
|
83
|
+
"agent-id",
|
|
84
|
+
messages=[{"role": "user", "content": "Tell me a story"}],
|
|
85
|
+
stream=True,
|
|
86
|
+
):
|
|
87
|
+
print(event.content, end="", flush=True)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Chat (Non-streaming)
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
response = client.agents.chat(
|
|
94
|
+
"agent-id",
|
|
95
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
96
|
+
user_id="user-123",
|
|
97
|
+
session_id="session-456", # optional, auto-created if omitted
|
|
98
|
+
)
|
|
99
|
+
print(response.content)
|
|
100
|
+
print(f"Tokens used: {response.usage.total_tokens}")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Chat (Advanced Options)
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
response = client.agents.chat(
|
|
107
|
+
"agent-id",
|
|
108
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
109
|
+
user_id="user-123",
|
|
110
|
+
user_display_name="Alex",
|
|
111
|
+
provider="openai",
|
|
112
|
+
model="gpt-4o",
|
|
113
|
+
language="en",
|
|
114
|
+
timezone="America/New_York",
|
|
115
|
+
compiled_system_prompt="You are a helpful assistant.",
|
|
116
|
+
tool_capabilities={"web_search": True, "remember_name": True, "image_generation": False},
|
|
117
|
+
tool_definitions=[
|
|
118
|
+
{"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}},
|
|
119
|
+
],
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Memory
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# Get memory tree
|
|
127
|
+
memory = client.agents.memory.list("agent-id", user_id="user-123")
|
|
128
|
+
for node in memory.nodes:
|
|
129
|
+
print(f"{node.title} (importance: {node.importance})")
|
|
130
|
+
|
|
131
|
+
# Search memories
|
|
132
|
+
results = client.agents.memory.search("agent-id", query="favorite food")
|
|
133
|
+
for fact in results.results:
|
|
134
|
+
print(f"{fact.content} (score: {fact.score})")
|
|
135
|
+
|
|
136
|
+
# Get memory timeline
|
|
137
|
+
timeline = client.agents.memory.timeline(
|
|
138
|
+
"agent-id",
|
|
139
|
+
user_id="user-123",
|
|
140
|
+
start="2026-01-01",
|
|
141
|
+
end="2026-03-01",
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Personality
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
personality = client.agents.personality.get("agent-id")
|
|
149
|
+
print(f"Name: {personality.profile.name}")
|
|
150
|
+
print(f"Openness: {personality.profile.big5.openness.score}")
|
|
151
|
+
print(f"Warmth: {personality.profile.dimensions.warmth}/10")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Sessions
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Start a session
|
|
158
|
+
client.agents.sessions.start(
|
|
159
|
+
"agent-id",
|
|
160
|
+
user_id="user-123",
|
|
161
|
+
session_id="session-456",
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# ... chat messages ...
|
|
165
|
+
|
|
166
|
+
# End a session
|
|
167
|
+
client.agents.sessions.end(
|
|
168
|
+
"agent-id",
|
|
169
|
+
user_id="user-123",
|
|
170
|
+
session_id="session-456",
|
|
171
|
+
total_messages=10,
|
|
172
|
+
duration_seconds=300,
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Agent Instances
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
# List instances
|
|
180
|
+
instances = client.agents.instances.list("agent-id")
|
|
181
|
+
|
|
182
|
+
# Create a new instance
|
|
183
|
+
instance = client.agents.instances.create("agent-id", name="Test Instance")
|
|
184
|
+
print(f"Created: {instance.instance_id}")
|
|
185
|
+
|
|
186
|
+
# Reset an instance
|
|
187
|
+
client.agents.instances.reset("agent-id", instance.instance_id)
|
|
188
|
+
|
|
189
|
+
# Delete an instance
|
|
190
|
+
client.agents.instances.delete("agent-id", instance.instance_id)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Notifications
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# Get pending notifications
|
|
197
|
+
notifications = client.agents.notifications.list("agent-id", status="pending")
|
|
198
|
+
for n in notifications.notifications:
|
|
199
|
+
print(f"[{n.check_type}] {n.generated_message}")
|
|
200
|
+
|
|
201
|
+
# Consume a notification
|
|
202
|
+
client.agents.notifications.consume("agent-id", n.message_id)
|
|
203
|
+
|
|
204
|
+
# Get notification history
|
|
205
|
+
history = client.agents.notifications.history("agent-id")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Context Engine Data
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
# Mood
|
|
212
|
+
mood = client.agents.get_mood("agent-id", user_id="user-123")
|
|
213
|
+
|
|
214
|
+
# Relationships
|
|
215
|
+
relationships = client.agents.get_relationships("agent-id", user_id="user-123")
|
|
216
|
+
|
|
217
|
+
# Habits, Goals, Interests
|
|
218
|
+
habits = client.agents.get_habits("agent-id")
|
|
219
|
+
goals = client.agents.get_goals("agent-id")
|
|
220
|
+
interests = client.agents.get_interests("agent-id")
|
|
221
|
+
|
|
222
|
+
# Diary
|
|
223
|
+
diary = client.agents.get_diary("agent-id")
|
|
224
|
+
|
|
225
|
+
# Users
|
|
226
|
+
users = client.agents.get_users("agent-id")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Evaluation
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Evaluate an agent
|
|
233
|
+
result = client.agents.evaluate(
|
|
234
|
+
"agent-id",
|
|
235
|
+
messages=[
|
|
236
|
+
{"role": "user", "content": "I'm feeling sad today"},
|
|
237
|
+
{"role": "assistant", "content": "I'm sorry to hear that..."},
|
|
238
|
+
],
|
|
239
|
+
template_id="template-uuid",
|
|
240
|
+
)
|
|
241
|
+
print(f"Score: {result.score}")
|
|
242
|
+
print(f"Feedback: {result.feedback}")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Simulation
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# Run a simulation (streaming — launches run, then streams events)
|
|
249
|
+
for event in client.agents.simulate(
|
|
250
|
+
"agent-id",
|
|
251
|
+
user_persona={
|
|
252
|
+
"name": "Alex",
|
|
253
|
+
"background": "College student",
|
|
254
|
+
"personality_traits": ["curious", "friendly"],
|
|
255
|
+
"communication_style": "casual",
|
|
256
|
+
},
|
|
257
|
+
config={
|
|
258
|
+
"max_sessions": 3,
|
|
259
|
+
"max_turns_per_session": 10,
|
|
260
|
+
},
|
|
261
|
+
):
|
|
262
|
+
print(f"[{event.type}] {event.message}")
|
|
263
|
+
|
|
264
|
+
# Fire-and-forget (returns RunRef immediately)
|
|
265
|
+
ref = client.agents.simulate_async(
|
|
266
|
+
"agent-id",
|
|
267
|
+
user_persona={"name": "Alex", "background": "Student"},
|
|
268
|
+
config={"max_sessions": 2},
|
|
269
|
+
)
|
|
270
|
+
print(f"Run started: {ref.run_id}")
|
|
271
|
+
|
|
272
|
+
# Reconnect to stream later (supports resuming via from_index)
|
|
273
|
+
for event in client.eval_runs.stream_events(ref.run_id, from_index=0):
|
|
274
|
+
print(f"[{event.type}] {event.message}")
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Run Eval (Simulation + Evaluation)
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
# Combined simulation + evaluation
|
|
281
|
+
for event in client.agents.run_eval(
|
|
282
|
+
"agent-id",
|
|
283
|
+
template_id="template-uuid",
|
|
284
|
+
user_persona={"name": "Alex", "background": "Student"},
|
|
285
|
+
simulation_config={"max_sessions": 2, "max_turns_per_session": 5},
|
|
286
|
+
):
|
|
287
|
+
print(f"[{event.type}] {event.message}")
|
|
288
|
+
|
|
289
|
+
# Fire-and-forget
|
|
290
|
+
ref = client.agents.run_eval_async(
|
|
291
|
+
"agent-id",
|
|
292
|
+
template_id="template-uuid",
|
|
293
|
+
simulation_config={"max_sessions": 2},
|
|
294
|
+
)
|
|
295
|
+
print(f"Run started: {ref.run_id}")
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Re-evaluate (Eval Only)
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
# Re-evaluate an existing run with a different template
|
|
302
|
+
for event in client.agents.eval_only(
|
|
303
|
+
"agent-id",
|
|
304
|
+
template_id="new-template-uuid",
|
|
305
|
+
source_run_id="existing-run-uuid",
|
|
306
|
+
):
|
|
307
|
+
print(f"[{event.type}] {event.message}")
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Custom States
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
# Create a custom state
|
|
314
|
+
state = client.agents.custom_states.create(
|
|
315
|
+
"agent-id",
|
|
316
|
+
key="player_level",
|
|
317
|
+
value={"level": 15, "xp": 2400},
|
|
318
|
+
scope="user",
|
|
319
|
+
content_type="json",
|
|
320
|
+
user_id="user-123",
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# List states
|
|
324
|
+
states = client.agents.custom_states.list("agent-id", scope="global")
|
|
325
|
+
|
|
326
|
+
# Upsert by composite key (create or update)
|
|
327
|
+
state = client.agents.custom_states.upsert(
|
|
328
|
+
"agent-id",
|
|
329
|
+
key="player_level",
|
|
330
|
+
value={"level": 16, "xp": 3000},
|
|
331
|
+
scope="user",
|
|
332
|
+
user_id="user-123",
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Get by composite key
|
|
336
|
+
state = client.agents.custom_states.get_by_key(
|
|
337
|
+
"agent-id",
|
|
338
|
+
key="player_level",
|
|
339
|
+
scope="user",
|
|
340
|
+
user_id="user-123",
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Delete by composite key
|
|
344
|
+
client.agents.custom_states.delete_by_key(
|
|
345
|
+
"agent-id",
|
|
346
|
+
key="player_level",
|
|
347
|
+
scope="user",
|
|
348
|
+
user_id="user-123",
|
|
349
|
+
)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Eval Templates
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
# List templates
|
|
356
|
+
templates = client.eval_templates.list()
|
|
357
|
+
|
|
358
|
+
# Create a template
|
|
359
|
+
template = client.eval_templates.create(
|
|
360
|
+
name="Empathy Check",
|
|
361
|
+
scoring_rubric="Evaluate emotional awareness and response quality",
|
|
362
|
+
categories=[
|
|
363
|
+
{"name": "Emotional Awareness", "weight": 0.5, "criteria": "..."},
|
|
364
|
+
{"name": "Response Quality", "weight": 0.5, "criteria": "..."},
|
|
365
|
+
],
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# Update a template
|
|
369
|
+
client.eval_templates.update(template.id, name="Updated Name")
|
|
370
|
+
|
|
371
|
+
# Delete a template
|
|
372
|
+
client.eval_templates.delete(template.id)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Eval Runs
|
|
376
|
+
|
|
377
|
+
```python
|
|
378
|
+
# List eval runs
|
|
379
|
+
runs = client.eval_runs.list(agent_id="agent-id")
|
|
380
|
+
|
|
381
|
+
# Get a specific run
|
|
382
|
+
run = client.eval_runs.get("run-id")
|
|
383
|
+
print(f"Status: {run.status}, Turns: {run.total_turns}")
|
|
384
|
+
|
|
385
|
+
# Stream events from a running eval (reconnectable)
|
|
386
|
+
for event in client.eval_runs.stream_events("run-id"):
|
|
387
|
+
print(f"[{event.type}] {event.message}")
|
|
388
|
+
|
|
389
|
+
# Delete a run
|
|
390
|
+
client.eval_runs.delete("run-id")
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Async Support
|
|
394
|
+
|
|
395
|
+
Every method is also available as an async variant:
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
import asyncio
|
|
399
|
+
from sonzai import AsyncSonzai
|
|
400
|
+
|
|
401
|
+
async def main():
|
|
402
|
+
async with AsyncSonzai(api_key="your-api-key") as client:
|
|
403
|
+
# Non-streaming
|
|
404
|
+
response = await client.agents.chat(
|
|
405
|
+
"agent-id",
|
|
406
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
407
|
+
)
|
|
408
|
+
print(response.content)
|
|
409
|
+
|
|
410
|
+
# Streaming
|
|
411
|
+
async for event in await client.agents.chat(
|
|
412
|
+
"agent-id",
|
|
413
|
+
messages=[{"role": "user", "content": "Tell me a story"}],
|
|
414
|
+
stream=True,
|
|
415
|
+
):
|
|
416
|
+
print(event.content, end="", flush=True)
|
|
417
|
+
|
|
418
|
+
asyncio.run(main())
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Configuration
|
|
422
|
+
|
|
423
|
+
```python
|
|
424
|
+
client = Sonzai(
|
|
425
|
+
api_key="sk-...", # or SONZAI_API_KEY env var
|
|
426
|
+
base_url="https://api.sonz.ai", # or SONZAI_BASE_URL env var
|
|
427
|
+
timeout=30.0, # request timeout in seconds
|
|
428
|
+
max_retries=2, # retry count for failed requests
|
|
429
|
+
)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Error Handling
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
from sonzai import (
|
|
436
|
+
Sonzai,
|
|
437
|
+
AuthenticationError,
|
|
438
|
+
NotFoundError,
|
|
439
|
+
BadRequestError,
|
|
440
|
+
RateLimitError,
|
|
441
|
+
InternalServerError,
|
|
442
|
+
SonzaiError,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
try:
|
|
446
|
+
response = client.agents.chat("agent-id", messages=[...])
|
|
447
|
+
except AuthenticationError:
|
|
448
|
+
print("Invalid API key")
|
|
449
|
+
except NotFoundError:
|
|
450
|
+
print("Agent not found")
|
|
451
|
+
except RateLimitError:
|
|
452
|
+
print("Rate limit exceeded, try again later")
|
|
453
|
+
except SonzaiError as e:
|
|
454
|
+
print(f"API error: {e}")
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Development
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
# Clone the repo
|
|
461
|
+
git clone https://github.com/sonz-ai/sonzai-python.git
|
|
462
|
+
cd sonzai-python
|
|
463
|
+
|
|
464
|
+
# Install dev dependencies
|
|
465
|
+
pip install -e ".[dev]"
|
|
466
|
+
|
|
467
|
+
# Run tests
|
|
468
|
+
pytest
|
|
469
|
+
|
|
470
|
+
# Lint
|
|
471
|
+
ruff check src/
|
|
472
|
+
|
|
473
|
+
# Type check
|
|
474
|
+
mypy src/
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## License
|
|
478
|
+
|
|
479
|
+
MIT License - see [LICENSE](LICENSE) for details.
|