Metadata-Version: 2.4
Name: aegis-platform-sdk
Version: 0.2.0
Summary: AEGIS Ontology SDK — typed Python client + functional namespace (aegis.inference, aegis.iam, aegis.osdk)
Author: Safe-Core Technologies
License: Proprietary — Safe-Core Technologies
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx<1.0,>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: respx>=0.21; extra == "dev"

# aegis-sdk (Python)

Typed Python client + functional namespace for the AEGIS platform —
IAM, OSDK applications, ontology surface, LLM inference, RAG. Maps 1:1
to the HTTPS API documented in
[`docs/iam-rbac/07-endpoint-reference.md`](../docs/iam-rbac/07-endpoint-reference.md).

The package name on disk is **`aegis`** (the previous `aegis_sdk` is a
deprecation shim, removed in v0.3). Pip target stays
`aegis-sdk`.

## Install

```bash
pip install aegis-sdk
# or, from source while developing AEGIS:
pip install -e ./aegis-python-sdk
```

## Two ways to use

### Client style — explicit auth, structured access

```python
from aegis import AegisClient

# Issue an OSDK token in the AEGIS UI: Governance → OSDK Applications.
client = AegisClient(
    base_url="https://aegis.example.com",
    token="osdk_xK9pQzR2L8mYvN4w...",
)

me = client.auth.me()
print(me.username, me.permissions)        # → osdk:my-app, ["ontology.types.read", ...]

users = client.iam.users.list()
for u in users:
    print(u.username, u.roles)

nav = client.iam.nav.tree()
for s in nav.sections:
    print(s.id, "·", len(s.items), "items")
```

The OSDK token is shown **once** on creation. Treat it like a database
credential — rotate, never commit.

### Functional style — Palantir-like namespace

```python
from aegis import inference

# Auto-uses a default client built from AEGIS_API_URL / AEGIS_TOKEN env vars.
out = inference.complete("Summarise the latest threat indicators")
print(out["response_text"])

answer = inference.chat(
    messages=[{"role": "user", "content": "What intel exists on elections?"}],
    rag_sources=["telegram", "tiktok_comments"],
)

models = inference.models()
collections = inference.collections()
```

Pin a pre-authed client globally:

```python
import aegis
client = aegis.AegisClient(token="osdk_…")
aegis.set_default_client(client)

# Now every aegis.inference.* call uses the bearer.
aegis.inference.complete("hi")
```

Or pass it per-call:

```python
aegis.inference.complete("hi", client=my_client)
```

## Quick start — human auth (login)

```python
from aegis import AegisClient

client = AegisClient(base_url="https://aegis.example.com")
pair = client.auth.login(username="alice", password="…", totp_code="123456")
# JWT is now attached to the client; refresh handled by client.auth.refresh(...).

me = client.auth.me()
client.auth.change_password("…", "new-strong-pass-12+chars")
client.auth.logout(pair.refresh_token)
```

## Surface

| Group | Methods |
|-------|---------|
| `client.auth` | `login`, `me`, `refresh`, `logout`, `change_password` |
| `client.iam.users` | `list`, `get` |
| `client.iam.roles` | `list`, `get` |
| `client.iam.permissions` | `list(resource=…)` |
| `client.iam.nav` | `tree(as_role_id=…)` |
| `client.osdk` | `list`, `get`, `create(name, scopes, expires_at)`, `rotate`, `revoke` |
| `aegis.inference` (module-level) | `complete(prompt, …)`, `chat(messages, rag_sources=…)`, `models()`, `collections()`, `chat_with_rag(query, …)`, `audit_trail(limit, provider)` |

Write surfaces (PUT / PATCH / DELETE for users, roles, etc.) are on the
short-term roadmap — open an issue if you need them sooner.

## Errors

```python
from aegis import AegisClient, PermissionDeniedError, AuthError

try:
    client.iam.users.list()
except PermissionDeniedError as exc:
    print(f"missing perm: {exc.detail}")
except AuthError as exc:
    print(f"token expired or invalid: {exc.detail}")
```

Hierarchy: `AegisAPIError` ← `AuthError` (401) · `PermissionDeniedError` (403) · `NotFoundError` (404).

## Environment overrides

| Var | Effect |
|-----|--------|
| `AEGIS_API_URL` | default base URL when none is passed |
| `AEGIS_TOKEN` | default bearer token when none is passed |

## Development

```bash
cd aegis-python-sdk
pip install -e ".[dev]"
pytest -v
```

The unit suite uses `respx` to stub the HTTPS surface — no live stack
needed. The integration suite (under `tests/integration/`) runs against
a real ontology-module API at `$AEGIS_API_URL` and is skipped if the
service is unreachable.
