Metadata-Version: 2.4
Name: structx-sdk
Version: 0.2.0
Summary: Official Python SDK (structx-sdk) for struct-x — agent-native structured extraction.
Project-URL: Homepage, https://structx.ai
Project-URL: Documentation, https://docs.structx.ai
Project-URL: Repository, https://github.com/struct-x-ai/struct-x
Project-URL: Issues, https://github.com/struct-x-ai/struct-x/issues
Project-URL: Changelog, https://github.com/struct-x-ai/struct-x/blob/main/sdk/python/CHANGELOG.md
Author-email: struct-x <support@structx.ai>
License: MIT
License-File: LICENSE
Keywords: agent,ai,extraction,json-schema,llm,mcp,structured-extraction
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<0.29,>=0.27
Requires-Dist: pydantic<3.0,>=2.5
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# structx-sdk — Python SDK for struct-x

[![PyPI](https://img.shields.io/pypi/v/structx-sdk.svg)](https://pypi.org/project/structx-sdk/)
[![Python](https://img.shields.io/pypi/pyversions/structx-sdk.svg)](https://pypi.org/project/structx-sdk/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Official Python client for **[struct-x](https://structx.ai)** — the agent-native structured-extraction API. Send raw content and a JSON Schema, get back validated, typed JSON with per-field confidence scores.

## Install

```bash
pip install structx-sdk
```

## Quickstart

```python
from structx_sdk import StructX

client = StructX(api_key="sx_...")

result = client.extract(
    content="<div><h1>Aeron Chair</h1><span>$1,795.00</span></div>",
    schema={
        "type": "object",
        "required": ["title", "price_cents"],
        "properties": {
            "title":       {"type": "string"},
            "price_cents": {"type": "integer"},
        },
    },
)

print(result.data)
# {'title': 'Aeron Chair', 'price_cents': 179500}

print(result.field_confidences[0])
# FieldConfidence(field='title', confidence=0.96, source_snippet=None)
```

## Use a catalog template instead of an inline schema

```python
result = client.extract(
    content=stripe_webhook_payload,
    template_slug="logs.stripe.event",   # latest published version
)
```

Pin to a specific template version with `family_slug@version`:

```python
template_slug="logs.stripe.event@1.0.0"
```

## Don't have a schema yet? Let the API infer one

```python
inference = client.infer_schema(
    content="<html>… some product page …</html>",
    content_type="html",
)

print(inference.inferred.json_schema)   # ready to pass back to extract()
for f in inference.inferred.fields:
    print(f"{f.name} ({f.type}) — {f.rationale}")

# Plus template recommendations, if any matched:
for r in inference.recommendations:
    print(f"{r.slug} (score={r.score:.2f})")
```

## Async

Same surface, `await`-flavored:

```python
import asyncio
from structx_sdk import AsyncStructX

async def main():
    async with AsyncStructX(api_key="sx_...") as client:
        result = await client.extract(content="…", schema={…})
        print(result.data)

asyncio.run(main())
```

## Configuration

| Param          | Default                       | Notes                                                  |
|----------------|-------------------------------|--------------------------------------------------------|
| `api_key`      | `STRUCTX_API_KEY` env var     | Required.                                              |
| `base_url`     | `STRUCTX_BASE_URL` env var, else `https://api.structx.ai` | Override for staging / self-hosted. |
| `timeout`      | `30.0` seconds                | Applied per request.                                   |
| `retry`        | `RetryPolicy(max_attempts=3, …)` | Tune via `RetryPolicy(...)`.                        |
| `default_headers` | `{}`                       | Merged into every request — e.g., for tracing IDs.    |

Pick up credentials from the environment with `StructX.from_env()`:

```python
import os
os.environ["STRUCTX_API_KEY"] = "sx_..."

from structx_sdk import StructX
client = StructX.from_env()
```

## Errors

All exceptions inherit from `StructXError`. Catch the specific class you care about:

```python
from structx_sdk import RateLimitError, ValidationError, ServerError

try:
    result = client.extract(content=…, schema=…)
except RateLimitError as e:
    # 429 — back off; e.retry_after, e.credits_used, e.credits_remaining are populated
    print(f"Sleep {e.retry_after}s. Used {e.credits_used}/{e.credits_used + e.credits_remaining}.")
except ValidationError as e:
    # 400/422 — fix your input. e.code carries the machine-readable reason.
    print(f"Bad input: {e.code} — {e.message}")
except ServerError as e:
    # 5xx — retry or contact support; e.request_id is your handle.
    print(f"Server error (request_id={e.request_id})")
```

Full hierarchy:

```
StructXError
├── TransportError              # network failure — request never reached the server
└── ApiError                    # server responded with an error status
    ├── AuthenticationError     # 401
    ├── PermissionDeniedError   # 403
    ├── NotFoundError           # 404
    ├── ValidationError         # 400, 422
    ├── RateLimitError          # 429  (carries retry_after, credits info)
    └── ServerError             # 5xx
```

## Retries

By default, **read** calls (`list_templates`, `list_models`, `usage`) auto-retry on transient 5xx and connection errors with exponential backoff.

**Write** calls (`extract`, `infer_schema`) retry ONLY on transport errors, never on 5xx — because a 5xx after a partial backend run may have already billed the call.

Customize via `RetryPolicy`:

```python
from structx_sdk import StructX, RetryPolicy

client = StructX(
    api_key="sx_...",
    retry=RetryPolicy(
        max_attempts=5,
        initial_backoff=0.5,
        max_backoff=60.0,
        retry_on_5xx=True,
        respect_retry_after=True,
    ),
)
```

## Forward compatibility

Response models accept extra fields silently. When the API adds a new field, old SDK versions don't break — they just don't surface it as a typed attribute. Reach it via `result.model_dump()` or `result.__pydantic_extra__`.

## Development

```bash
git clone https://github.com/struct-x-ai/struct-x
cd struct-x/sdk/python
pip install -e ".[dev]"
pytest -q
```

## License

MIT — see [LICENSE](LICENSE).
