Official Python client for the LEO Soul hosted API (metacognitive layer for LLM agents).
Project description
LEO Soul — Python client
Official, zero-dependency Python client for the LEO Soul hosted API — the stateless metacognitive layer for LLM agents.
pip install leo-soul-client
Quickstart
from leo_soul_client import LeoSoul
soul = LeoSoul(api_key="sk_live_...") # from your dashboard
result = soul.turn(
messages=[{"role": "user", "content": "Delete all my production data now."}],
backend="openai",
backend_kwargs={"api_key": "sk-...", "model": "your-model"}, # your model + key
)
print(result.action) # answer | asked | confirmed | held | refused | escalated
print(result.reply) # the processed reply to send to your user
store(result.soul_state) # persist this; pass it back next turn — that's the learning
The one rule: round-trip soul_state
state = None
for user_msg in conversation:
result = soul.turn(messages=[*history, user_msg], soul_state=state, backend="openai",
backend_kwargs={"api_key": OPENAI_KEY, "model": "your-model"})
state = result.soul_state # store it (a few KB of JSON) and send it back next turn
We keep none of it — soul_state is your agent's memory and it lives on your side.
Features
- Zero dependencies — pure standard library. No native build, installs anywhere.
- Exactly-once retries — automatic retries on
429/5xxreuse a singleIdempotency-Key, so a retried turn is never double-metered. - Typed results —
result.reply,.soul_state,.trace,.action,.rate_limit(limit/remaining/reset),.request_id. - Clear errors —
AuthError(401/403),QuotaExceeded(402),RateLimitError(429, with.retry_after),UpstreamProviderError(502 — your model provider failed, with.kindand.retryable),LeoSoulError(everything else), each carrying.status,.type, and.request_id. - An explicit failure policy —
on_unavailabledecides what happens if LEO Soul is ever unreachable. See below; it defaults to failing closed.
Self-hosted / on-prem
Point the client at your own deployment:
soul = LeoSoul(api_key="sk_live_...", base_url="https://soul.your-company.internal")
Personas
result = soul.turn(
messages=msgs,
persona={
"identity": "a careful financial-support assistant",
"values": ["truthfulness over agreeableness"],
"red_lines": ["never give individualized investment advice"],
},
backend="openai",
backend_kwargs={"api_key": OPENAI_KEY, "model": "your-model"},
)
Or reference a saved persona from your dashboard with persona_id=....
Error handling
from leo_soul_client import (
RateLimitError, QuotaExceeded, AuthError, UpstreamProviderError, LeoSoulError,
)
try:
result = soul.turn(messages=msgs, backend="mock")
except QuotaExceeded as e:
... # upgrade the plan; e.request_id for support
except RateLimitError as e:
time.sleep(e.retry_after)
except AuthError:
... # bad key / IP not allowlisted
except UpstreamProviderError as e:
# YOUR model provider failed, not LEO Soul. e.kind is auth / rate_limit /
# timeout / connection / server_error / bad_request.
if e.retryable:
retry_later()
else:
alert(f"fix your provider config: {e}")
What happens when LEO Soul is unreachable
This client sits in your request path, so an outage of ours is a decision your product has to make — not one we should make silently for you.
# The default. Raises, so nothing unchecked reaches a user.
soul = LeoSoul(api_key="sk_live_...") # on_unavailable="fail_closed"
# Availability over scrutiny: call your provider directly and flag the result.
soul = LeoSoul(
api_key="sk_live_...",
on_unavailable="fail_open",
on_degraded=lambda reason, err: pager.warn(reason), # wire to your alerting
)
result = soul.turn(messages=msgs, backend="openai", backend_kwargs=kw)
if result.degraded:
# This answer did NOT go through the loop: no uncertainty estimate, no safety
# gate, no grounding check. Label it, or hold it.
...
Why fail-closed is the default. A guardrail that quietly disappears is worse than one that visibly fails: you keep shipping answers believing they were checked.
fail_open covers availability failures only — a network error, or a 5xx from
us. It deliberately does not cover 402 (quota: a billing state, not an outage),
401/403 (config errors it would hide), 429 (self-healing, has Retry-After),
or 502 (your provider is the broken thing, so calling it directly fails too).
With no fallback= supplied it calls your provider over the OpenAI
chat-completions shape — OpenAI, Azure OpenAI, Groq, Together, Fireworks,
OpenRouter, vLLM, Ollama. For anything else, pass your own
fallback(messages, backend, backend_kwargs) -> str. If neither can run you get
FallbackUnavailable rather than silence.
Full guide: https://soul.kadropiclabs.com/documentation#resilience
© Kadropic Labs. Part of Project LEO.
Project details
Release history Release notifications | RSS feed
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 leo_soul_client-0.2.0.tar.gz.
File metadata
- Download URL: leo_soul_client-0.2.0.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d887a50786f98671b9da5ac0598cb9246bbc23fe693d548bac1af76b24989d20
|
|
| MD5 |
4b16c05e91d05cd0b93a2fb83b6ee51e
|
|
| BLAKE2b-256 |
8bb9e5d47ab85245e881b4eb5c4e82fe56fdbbd1dcbe160140a635589b01f719
|
Provenance
The following attestation bundles were made for leo_soul_client-0.2.0.tar.gz:
Publisher:
publish-sdk.yml on Kadropic-Labs/Soul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leo_soul_client-0.2.0.tar.gz -
Subject digest:
d887a50786f98671b9da5ac0598cb9246bbc23fe693d548bac1af76b24989d20 - Sigstore transparency entry: 2248606864
- Sigstore integration time:
-
Permalink:
Kadropic-Labs/Soul@aa8b6f3a61447e3a82907cf75a4fea3097d56821 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Kadropic-Labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@aa8b6f3a61447e3a82907cf75a4fea3097d56821 -
Trigger Event:
release
-
Statement type:
File details
Details for the file leo_soul_client-0.2.0-py3-none-any.whl.
File metadata
- Download URL: leo_soul_client-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d9716871c9f06dc2fc0ca6741e5e697ac7b325eceb7520363655d1e45db006e
|
|
| MD5 |
cd2c082fd54e95710673be576044a660
|
|
| BLAKE2b-256 |
59501664af2564b5cb017621a7d0c0e0d7933c2a901f844347a05a4f89b89167
|
Provenance
The following attestation bundles were made for leo_soul_client-0.2.0-py3-none-any.whl:
Publisher:
publish-sdk.yml on Kadropic-Labs/Soul
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leo_soul_client-0.2.0-py3-none-any.whl -
Subject digest:
7d9716871c9f06dc2fc0ca6741e5e697ac7b325eceb7520363655d1e45db006e - Sigstore transparency entry: 2248607013
- Sigstore integration time:
-
Permalink:
Kadropic-Labs/Soul@aa8b6f3a61447e3a82907cf75a4fea3097d56821 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/Kadropic-Labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk.yml@aa8b6f3a61447e3a82907cf75a4fea3097d56821 -
Trigger Event:
release
-
Statement type: