Metadata-Version: 2.4
Name: ada-grpc-sdk
Version: 0.0.1
Summary: Strictly typed Ada gRPC SDK for Python
Author: eleven-am
License-Expression: MIT
Project-URL: Source, https://github.com/eleven-am/ada-sdk
Project-URL: Issues, https://github.com/eleven-am/ada-sdk/issues
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: grpcio==1.83.0
Requires-Dist: protobuf==7.35.1
Requires-Dist: typing-extensions==4.16.0
Provides-Extra: dev
Requires-Dist: build==1.5.0; extra == "dev"
Requires-Dist: mypy==2.3.0; extra == "dev"
Requires-Dist: pip-audit==2.10.1; extra == "dev"
Requires-Dist: pytest==9.1.1; extra == "dev"
Requires-Dist: types-grpcio==1.82.1.20260724; extra == "dev"
Requires-Dist: types-protobuf==7.34.1.20260518; extra == "dev"
Dynamic: license-file

# Ada SDK for Python

`AdaClient` represents one authenticated namespace. Its cached principal facades share one gRPC channel and one lazy, persistent namespace stream for events, signals, and jobs.

## Installation

```sh
python -m pip install ada-grpc-sdk
```

Python 3.10 or newer is required. Construct the namespace client only in trusted backend code; `api_key` or `api_key_provider` authenticates the whole namespace.

## Backend client

```python
import os

from ada_sdk import AdaClient, StreamConfig, SubscriptionOptions

with AdaClient(
    "memory.example.com:443",
    api_key=os.environ["ADA_API_KEY"],
    streams=StreamConfig(
        events=SubscriptionOptions(
            after_event_id=saved_event_cursor,
            replay_limit=100,
        ),
        signals=SubscriptionOptions(after_event_id=saved_signal_cursor),
        jobs=SubscriptionOptions(after_event_id=saved_job_cursor),
    ),
) as ada:
    alice = ada.principal("alice")
    bob = ada.principal("bob")

    stop_alice = alice.events.on(
        "memory.ingest.finished",
        lambda event: print(event.document_id),
    )
    stop_bob = bob.signals.on(
        "routine.broken",
        lambda signal: print(signal),
    )
    stop_job = alice.jobs.on(
        "job.finished",
        lambda event: print(event),
    )

    stop_alice()
    stop_alice()
    stop_bob()
    stop_job()
```

Every event-name overload selects an exact generated protobuf payload type and returns an idempotent synchronous unsubscribe callable. Strict mypy fixtures reject unknown event names, mismatched payloads, `open()`, root data-plane calls, and principal creation on a browser client.

All ingest, recall, document, job, data, and summary operations live on the principal facade:

```python
result = alice.ingest(ingest_pb2.IngestRequest(document=document))
status = alice.documents.get_status(
    ingest_pb2.GetDocumentStatusRequest(document_id=document_id),
)
```

The facade overwrites every request principal. Public-event and signal catalogs remain on the root through `get_public_event_catalog()` and `get_signal_catalog()`.

Replay cursors, reconnect policy, lifecycle handlers, and shutdown live on the root:

```python
stop_cursor = ada.lifecycle.on(
    "stream.cursor",
    lambda info: save_cursor(
        info.stream,
        info.event_id,
        info.principal_id,
    ),
)
stop_terminal = ada.lifecycle.on(
    "stream.terminal",
    lambda info: report_failure(info.stream, info.error),
)
```

`close()` and the context manager perform idempotent graceful shutdown and prevent later registrations.

`AdaBrowserClient(endpoint, session_token=...)` is a separate principal-bound client. It accepts no namespace API key and has no `principal()` method. Use it only with a short-lived browser session minted by a trusted backend.

Never embed a namespace API key in browser or otherwise untrusted client code. The TypeScript package is the supported browser/gRPC-Web implementation.
