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.
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .env
12
+ .mypy_cache/
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ *.so
16
+ .DS_Store
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
+ [![PyPI version](https://img.shields.io/pypi/v/sonzai.svg)](https://pypi.org/project/sonzai/)
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
36
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](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.