Metadata-Version: 2.4
Name: cognethics
Version: 0.1.3
Summary: Official Python SDK for the Cognethics platform
Project-URL: Homepage, https://developers.cognethics.com
Project-URL: Documentation, https://developers.cognethics.com
Author-email: Cognethics <noreply@cognethics.com>
License: Proprietary
License-File: LICENSE
Keywords: agents,cognethics,mcp,platform,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: typing-extensions>=4.0
Provides-Extra: dev
Requires-Dist: anyio>=4.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# cognethics

Official Python SDK for the Cognethics platform. `cognethics` provides an ergonomic, typed client for calling the platform's MCP-style handlers — entity CRUD, document operations, workflow actions, reports, and agent commands — over HTTPS, with API-key auth, organization scoping, pagination helpers, and structured error types.

## Installation

```bash
pip install cognethics
```

## Quickstart

```python
from cognethics import Client

client = Client(
    api_key="ck_...",
    base_url="https://gtm.cognethics.com",
)

invoices = client.invoices.list(page_size=10)
print(invoices["data"])
```

## Authentication

The SDK accepts two API-key prefixes:

- **`ck_...`** (recommended) — works for the Developer Sandbox surface (`/api/v1/dev/*`) **and** all MCP handlers. Mint one in the platform UI under **Settings → API Keys**.
- **`mcp_...`** (legacy) — works for MCP handlers only. Existing keys keep working but cannot call `/api/v1/dev/*`.

Pass the key via the `api_key` constructor argument:

```python
client = Client(api_key="ck_...", base_url="https://gtm.cognethics.com")
```

The client logs a one-line warning if the prefix is unrecognized; nothing is enforced client-side beyond that — the server is the source of truth.

OAuth-based authentication is planned for v0.2.

## Async client

`AsyncClient` mirrors `Client` for `asyncio` workloads. It uses `httpx.AsyncClient` under the hood and shares the same retry/timeout semantics.

```python
import asyncio
from cognethics import AsyncClient

async def main():
    async with AsyncClient(api_key="ck_...", base_url="https://gtm.cognethics.com") as c:
        result = await c.call(
            "prism_entity_crud",
            app="spare_parts",
            entity="work_order",
            operation="list",
        )
        print(result["data"])

asyncio.run(main())
```

> **MVP note:** `AsyncClient` exposes `await c.call(tool, **params)` only. The generated tree (`c.entity_crud.spare_parts...`) and the `c.dev` namespace are sync-only today — both are tracked for v0.2.

## Developer Sandbox (`client.dev`)

The `dev` namespace targets the unauthenticated/light-auth `/api/v1/dev/` surface and is the fastest way to verify a `ck_` key works:

```python
from cognethics import Client

client = Client(api_key="ck_...", base_url="https://gtm.cognethics.com")

# 1. Liveness probe — no auth required
client.dev.ping()
# → {"service": "cognethics-dev-api", "version": "v1", "status": "ok"}

# 2. Verify your key + identity context
client.dev.me()
# → {"authenticated": True, "key": {...}, "user": {...}, "tenant": {...}}

# 3. Echo arbitrary query params (debug helper)
client.dev.echo("hello", foo="bar")
```

`client.dev` errors raise the same exception classes used elsewhere in the SDK (`AuthenticationError`, `PermissionDenied`, `NotFound`, etc.), plus a catch-all `DevApiError` for unmapped 4xx codes.

## Calling low-level handlers

Every MCP handler exposed by the Cognethics platform is reachable in two ways:

```python
# 1. Generic dispatch — useful for handlers not yet covered by the codegen tree.
result = client.call(
    "prism_entity_crud",
    app="spare_parts",
    entity="work_order",
    operation="list",
)

# 2. Generated tree — type-friendly attribute access for entity_crud handlers.
result = client.entity_crud.spare_parts.work_order.list(page_size=10)
```

The generated tree is produced from the platform's introspection schema, so new entities show up automatically when the SDK is regenerated.

## Pagination

Use the `paginate` helper to iterate through multi-page results without managing cursors yourself:

```python
for row in client.paginate(client.invoices.list, page_size=50):
    print(row["id"], row["amount"])
```

## Error handling

The SDK raises typed exceptions that map to the platform's standard error envelope:

```python
import cognethics

try:
    # Generated update methods take a `data` dict for the update payload.
    client.entity_crud.finance.invoice.update(
        id="<invoice-uuid>",
        data={"status": "paid"},
    )
except cognethics.PermissionDenied:
    print("This API key cannot update invoices in this org.")
except cognethics.NotFound:
    print("Invoice does not exist.")
except cognethics.ValidationError as exc:
    print(f"Invalid payload: {exc}")
```

## Org switching

The Cognethics platform is multi-tenant and multi-org. The active org depends on auth method:

- **API-key auth (this version)**: each API key is bound to one organization at creation time. To access a different org, mint a separate API key for that org. The `org=` constructor argument and `_org=` per-call override are sent as `X-Organization-Context` but are silently ignored by the API-key auth path.
- **OAuth (planned for v0.2)**: the `org=` argument and `_org=` per-call override will switch the active organization for OAuth-issued bearer tokens.

```python
# v0.1: one API key per org
constance_client = Client(api_key="ck_constance_key", base_url="https://gtm.cognethics.com")
acme_client = Client(api_key="ck_acme_key", base_url="https://gtm.cognethics.com")
```

## Examples

Two runnable smoke tests live under `examples/`:

| Script | What it does |
|---|---|
| `examples/01_list_overdue_invoices.py` | Lists customer invoices with `status=overdue` via the generated tree. |
| `examples/02_create_work_order.py` | Creates a maintenance work order. Requires a real `spare_parts.item` UUID (`COGNETHICS_DEMO_ITEM_ID`). |

Run them with the SDK installed in your venv:

```bash
COGNETHICS_API_KEY=mcp_... \
COGNETHICS_BASE_URL=http://localhost:8000 \
python examples/01_list_overdue_invoices.py

COGNETHICS_API_KEY=mcp_... \
COGNETHICS_BASE_URL=http://localhost:8000 \
COGNETHICS_DEMO_ITEM_ID=<spare-parts-item-uuid> \
python examples/02_create_work_order.py
```

## Timeout & retry configuration

Both `Client` and `AsyncClient` retry on `429`, `502`, `503`, and `504` with exponential backoff (base 0.5s, doubling). `Retry-After` headers are honored on `429`. Defaults:

| Setting       | Default | Constructor arg |
| ------------- | ------- | --------------- |
| Timeout       | 30s     | `timeout=...`   |
| Max retries   | 3       | `max_retries=...` |

When retries are exhausted on a `429`, the SDK raises `RateLimit` with the `retry_after` field populated:

```python
from cognethics import Client, RateLimit

client = Client(api_key="ck_...", timeout=60.0, max_retries=5)

try:
    client.dev.me()
except RateLimit as exc:
    print(f"throttled — retry after {exc.retry_after}s")
```

## Limitations

- `AsyncClient` ships only `await c.call(tool, **params)` today. Generated tree (`c.entity_crud.*`) and `c.dev` namespace are sync-only and tracked for v0.2.
- Some handlers in `integration_call`, `document_op`, `notification_send`, and `config_manage` may not signature-filter unknown kwargs. Only pass parameters declared in the introspect schema for those handlers.
- The SDK uses raw dicts for request and response bodies; pydantic models are intentionally not in the dependency footprint.

## Documentation

Full API reference and guides: <https://developers.cognethics.com>
