Metadata-Version: 2.4
Name: atlanai
Version: 0.2.1
Summary: Unified Atlan Agent Gateway management and tracing SDK
License-Expression: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: pydantic<3,>=2.10
Requires-Dist: python-dateutil<3,>=2.8.2
Requires-Dist: typing-extensions<5,>=4.12
Requires-Dist: urllib3<3,>=2.3
Provides-Extra: tracing
Requires-Dist: opentelemetry-api<2,>=1.39.0; extra == "tracing"
Requires-Dist: opentelemetry-sdk<2,>=1.39.0; extra == "tracing"
Requires-Dist: opentelemetry-exporter-otlp-proto-http<2,>=1.39.0; extra == "tracing"
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3; extra == "langchain"

# atlanai

Python SDK for the Atlan Agent Gateway: manage agents, skills, sessions, and
workspaces, and optionally trace what your agents do.

## Install

```bash
pip install atlanai
```

Tracing is a separate extra — it pulls in OpenTelemetry, which a management-only
install doesn't need:

```bash
pip install 'atlanai[tracing]'
```

## Quickstart

```python
from atlanai import AtlanClient

client = AtlanClient(
    "https://<your-gateway-host>",
    bearer_token="<your-api-token>",
)

agent = client.agents.create({
    "name": "support-triage",
    "workspace_id": "workspace_01example",
})

page = client.agents.list(limit=10)
print(f"{len(page.items)} agents")
```

Methods read as `client.<resource>.<action>` — `client.agents.get(agent_id)`,
`client.sessions.messages.create(session_id, {...})`, and so on. Every public
Agent Gateway operation is reachable this way; nothing requires reaching into
a generated client directly.

Pass a default workspace once instead of repeating it on every call:

```python
client = AtlanClient(gateway_url, bearer_token=token, workspace="workspace_01example")
```

## Start an eval run

Resolve an existing dataset by artifact ID or exact name, then create the
Registry experiment before the runner emits any traces:

```python
from atlanai import ContextItem, ContextManifest, start_experiment

context = ContextManifest([
    ContextItem(
        kind="file",
        name="CLAUDE.md",
        version="git:0123456789abcdef0123456789abcdef01234567",
        digest="sha256:" + "0" * 64,
    ),
])

run = start_experiment(
    client,
    "conversational-studio-daily",  # exact name, or dataset_... ID
    {"name": "candidate-run", "config": {"model": "example-model"}},
    context_manifest=context,
)

with run.trace():
    output = existing_runner()
```

`run.experiment` is the generated create response and `run.id` is its
`experiment_id`. The helper pins the resolved dataset version and context
manifest in the immutable experiment config. `run.trace()` reuses the tracing
SDK to stamp only the experiment join and context-manifest digest on spans.
Execution, result upload, summarization, and terminal status remain the existing
`client.experiments` operations.

## Tracing

```python
import atlanai.tracing as atlan

tracer = atlan.init(api_key="<your-tracing-key>", workspace_id="workspace_01example")

with tracer.start_as_current_span("handle-request", as_type="task") as span:
    span.update(model="claude-sonnet-5", usage={"input_tokens": 120, "output_tokens": 40})
```

Tracing has its own API key and lifecycle — it does not reuse the management
client's bearer token or transport.

## Errors

Every non-2xx response raises `AtlanAPIError`, with `.status`, `.code`, and
(where the gateway includes one) `.trace_id`:

```python
from atlanai import AtlanAPIError

try:
    client.agents.get("agent_does_not_exist")
except AtlanAPIError as error:
    print(error.status, error.code)
```
