Official Python SDK for the Ensoul API. Build AI NPCs and personas with memory and personality that evolve through real conversation, scale to thousands, and run simulations where they change over time.
Project description
Ensoul Python SDK
Official Python SDK for the Ensoul API. Build AI personas and NPCs with memory and personality that evolve through real conversation. Scale to thousands of personas, and run simulations where they grow and change over time.
Installation
Requires Python 3.11 or newer. On Python 3.9 or 3.10, pip install ensoul fails with no compatible version. Check your version with python --version and upgrade if needed.
pip install ensoul
Quick Start
from ensoul import Ensoul
client = Ensoul(api_key="your-api-key")
# Create a persona
persona = client.personas.create(name="Alex", domain="my_domain")
# Send a chat message
response = client.chat.send(persona.id, "Hello, who are you?")
print(response.response)
The API key can also be set via the ENSOUL_API_KEY environment variable, in which case no api_key argument is needed.
The client supports context managers for automatic cleanup:
with Ensoul(api_key="your-api-key") as client:
persona = client.personas.get("persona-id")
Async Usage
import asyncio
from ensoul import AsyncEnsoul
async def main():
async with AsyncEnsoul(api_key="your-api-key") as client:
persona = await client.personas.create(name="Jordan", domain="my_domain")
response = await client.chat.send(persona.id, "Tell me about yourself.")
print(response.response)
asyncio.run(main())
Streaming
Chat supports server-sent events (SSE) for streaming responses. Each event's
data is a JSON object. The delta text lives in the chunk field:
| Field | Type | Notes |
|---|---|---|
chunk |
str |
The text delta. Append these to build the full reply. |
conversation_id |
str |
Stable across the stream. Pass it back to continue the conversation. |
chunk_index |
int |
0-based position of this chunk in the stream. |
is_final |
bool |
True on the last event. Its chunk is empty (""). |
token_usage |
dict | None |
Present only on the final event. |
Use parse_chat_event to turn each raw SSEEvent into a typed ChatStreamEvent,
then print chunk as it arrives:
from ensoul import Ensoul
from ensoul.streaming import parse_chat_event
client = Ensoul(api_key="your-api-key")
stream = client.chat.stream("persona-id", "What do you think about music?")
try:
for event in stream.events():
parsed = parse_chat_event(event)
print(parsed.chunk, end="", flush=True) # print text as it streams
if parsed.is_final:
print() # newline after the stream completes
if parsed.token_usage:
print(f"tokens: {parsed.token_usage}")
finally:
stream.close()
The async client returns an AsyncSSEStream that works the same way with async for:
import asyncio
from ensoul import AsyncEnsoul
from ensoul.streaming import parse_chat_event
async def main() -> None:
client = AsyncEnsoul(api_key="your-api-key")
stream = await client.chat.stream("persona-id", "What do you think about music?")
async for event in stream:
parsed = parse_chat_event(event)
print(parsed.chunk, end="", flush=True)
if parsed.is_final:
print()
asyncio.run(main())
Pagination
List endpoints return a SyncPage (or AsyncPage) object. Use .auto_paging_iter() to iterate through all pages automatically:
# Manual page access
page = client.personas.list(per_page=50)
print(page.items) # current page items
print(page.total) # total count across all pages
# Automatic pagination — fetches subsequent pages as needed
for persona in client.personas.list().auto_paging_iter():
print(persona.name)
Async pagination works the same way with async for.
Error Handling
All SDK errors inherit from EnsoulError. HTTP errors are subclasses of APIError:
from ensoul.errors import (
EnsoulError,
APIError,
AuthenticationError,
AuthorizationError,
NotFoundError,
RateLimitError,
ValidationError,
ConflictError,
ServerError,
)
try:
persona = client.personas.get("nonexistent-id")
except NotFoundError:
print("Persona not found")
except AuthenticationError:
print("Invalid or missing API key")
except RateLimitError:
print("Rate limit exceeded — back off and retry")
except APIError as e:
print(f"API error {e.status_code}: {e.message}")
Configuration
The client reads two environment variables as defaults:
| Variable | Purpose |
|---|---|
ENSOUL_API_KEY |
API key (avoids passing api_key= in code) |
ENSOUL_BASE_URL |
API base URL (default: https://api.ensoul-ai.com) |
Demo API — the current hosted demo is available at:
export ENSOUL_BASE_URL="https://api.demo.ensoul-ai.com"
export ENSOUL_API_KEY="your-api-key"
With these set, Ensoul() connects to the demo with no constructor arguments.
You can also pass the base URL explicitly:
client = Ensoul(api_key="ens_...", base_url="https://api.demo.ensoul-ai.com")
Authentication
API key (recommended):
client = Ensoul(api_key="ens_...")
# or set ENSOUL_API_KEY in the environment
client = Ensoul()
Bearer token:
client = Ensoul(bearer_token="eyJ...")
OAuth2 token exchange (password flow, form-encoded):
token_response = client.auth.token(
username="you@example.com",
password="your-password",
)
authed_client = Ensoul(bearer_token=token_response.access_token)
Resources
| Namespace | Description |
|---|---|
client.personas |
CRUD, list (paginated), batch create, personality vectors, filters, connections |
client.chat |
Send messages, streaming SSE, conversation history |
client.domains |
Domain configuration management |
client.simulations |
Time-based evolution simulations |
client.aggregate |
Aggregate queries with streaming results |
client.memory |
Persona memory management |
client.sessions |
Hierarchical session orchestration |
client.frameworks |
Framework management |
client.auth |
OAuth2 token exchange and API key management |
client.health |
Service health checks |
client.info |
Server info and configuration |
Requirements
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ensoul-0.2.5.tar.gz.
File metadata
- Download URL: ensoul-0.2.5.tar.gz
- Upload date:
- Size: 78.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5d3a9dc5d59f78e2f3f924f04bf75bd74806f01c8c5ce3d47dfabf781c86057
|
|
| MD5 |
dc6e13325b69b8e52f2388874d8c1e0d
|
|
| BLAKE2b-256 |
f9957d68cea2b9f57d9d2944b6789934dbfb84311fce1a191b0338ea0e9aad63
|
Provenance
The following attestation bundles were made for ensoul-0.2.5.tar.gz:
Publisher:
sdk-publish.yml on ensoul-ai/ensoul-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ensoul-0.2.5.tar.gz -
Subject digest:
c5d3a9dc5d59f78e2f3f924f04bf75bd74806f01c8c5ce3d47dfabf781c86057 - Sigstore transparency entry: 1854617801
- Sigstore integration time:
-
Permalink:
ensoul-ai/ensoul-sdk@e248b1d2357b6f767c35c6147c602f63cdef5619 -
Branch / Tag:
refs/tags/v0.2.5 - Owner: https://github.com/ensoul-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-publish.yml@e248b1d2357b6f767c35c6147c602f63cdef5619 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ensoul-0.2.5-py3-none-any.whl.
File metadata
- Download URL: ensoul-0.2.5-py3-none-any.whl
- Upload date:
- Size: 51.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b9764c77b8a88991031807229891330c07b5572b64c841a5ce44bbf664298c3
|
|
| MD5 |
38f32dda292c49a13658795c91618047
|
|
| BLAKE2b-256 |
cac773a9d1a2e3e079d93180114ea3ee2287af92368f263cc60354acbf6f4dc5
|
Provenance
The following attestation bundles were made for ensoul-0.2.5-py3-none-any.whl:
Publisher:
sdk-publish.yml on ensoul-ai/ensoul-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ensoul-0.2.5-py3-none-any.whl -
Subject digest:
3b9764c77b8a88991031807229891330c07b5572b64c841a5ce44bbf664298c3 - Sigstore transparency entry: 1854617830
- Sigstore integration time:
-
Permalink:
ensoul-ai/ensoul-sdk@e248b1d2357b6f767c35c6147c602f63cdef5619 -
Branch / Tag:
refs/tags/v0.2.5 - Owner: https://github.com/ensoul-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-publish.yml@e248b1d2357b6f767c35c6147c602f63cdef5619 -
Trigger Event:
push
-
Statement type: