Metadata-Version: 2.4
Name: eolaswork
Version: 0.1.6
Summary: Official Python SDK for the EolasWork agentic platform
Project-URL: Homepage, https://eolaswork.com
Project-URL: Documentation, https://docs.eolaswork.com/sdk/python
Project-URL: Repository, https://github.com/eolasflow/eolaswork-python
Author: EolasWork
License: MIT
Keywords: agents,ai,automation,eolaswork,llm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.11
Requires-Dist: httpx-sse<1.0,>=0.4
Requires-Dist: httpx<1.0,>=0.27
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# eolaswork

Official Python SDK for the [EolasWork](https://eolaswork.com) agentic platform.

## Install

```
pip install eolaswork
```

Python 3.11+. Sync + async clients ship together.

## Two ways to run agents

| Use case | Method | What it does |
|---|---|---|
| Chat with file attachments + history | `client.tasks.send_message(task_id, ...)` | Creates a turn + run bound to an existing task; agent sees uploaded files + prior messages. |
| Fire-and-forget standalone agent | `client.runs.create(...)` | Independent run; no task / file context. Good for cron-style jobs. |

The model used for each run is fixed by the chosen role or team's manifest
(`default_model`). There is no per-call model override today; if your tenant
has multiple models wired up, change the role's manifest to switch.

## Quickstart: chat with attachments

```python
from eolaswork import Client

client = Client(api_key="nxa_...")        # or set EOLASWORK_API_KEY

# 1. Discover what's available
me     = client.account.whoami()
roles  = client.roles.list()              # pick a role.slug for the run
models = client.models.list()             # each Model has .id (UUID), .display_name, .provider

# 2. Create the task (bound to an agent + first message in one call)
task = client.tasks.create(
    role="research-analyst",                # role.slug from client.roles.list()
    first_message="Build a board-ready summary from the Excel I'll upload.",
    subject="Q2 board prep",                # optional label
)

# 3. Attach files to the task (the agent sees them on next turns)
client.files.upload(task.id, "./Q2_sales.xlsx")

# 4. Send the follow-up turn that asks the agent to use the file
task = client.tasks.send_message(
    task.id,
    text="The Excel is uploaded - produce the board summary now.",
)

# 5. Wait for the latest run to finish (or stream events live)
final = client.runs.wait(task.last_run_id, timeout=300)
print(final.status, final.output)

# Streaming alternative:
for ev in client.runs.stream(task.last_run_id):
    print(ev.kind, ev.payload)
```

## Quickstart: standalone run (no task / files)

```python
run = client.runs.create(
    prompt="Summarise today's INGEST team Slack channel.",
    role="research-analyst",                       # role.slug
    webhook_url="https://my-app.example.com/eolaswork/hook",  # optional
)

# Three ways to handle completion:
final = client.runs.wait(run.id, timeout=300)               # blocks
# OR live SSE:
for ev in client.runs.stream(run.id): print(ev.kind, ev.payload)
# OR don't wait - your webhook receiver gets the HMAC-signed POST.

print(final.status, final.output)
```

## Async

```python
import asyncio
from eolaswork import AsyncClient

async def main():
    async with AsyncClient(api_key="nxa_...") as client:
        task = await client.tasks.create(title="async run")
        run = await client.tasks.send_message(
            task.id, prompt="hello", role="research-analyst",
        )
        async for ev in client.runs.astream(run.id):
            print(ev)

asyncio.run(main())
```

## Webhook receiver

```python
from eolaswork.webhooks import verify_signature

@app.post("/eolaswork/hook")
def hook(request):
    payload = verify_signature(
        raw_body=request.body,
        signature_header=request.headers["X-EolasWork-Signature"],
        secret=os.environ["EOLASWORK_WEBHOOK_SECRET"],
    )
    print(payload.run_id, payload.status, payload.output)
    return "", 204
```

## Configuration

| Env var | Default | Meaning |
|---|---|---|
| `EOLASWORK_API_KEY` | required | Bearer key (create at /settings/api-keys) |
| `EOLASWORK_BASE_URL` | `https://eolaswork.com` | Backend host (override for self-hosted / on-prem) |
| `EOLASWORK_PROXY` | unset | Explicit proxy URL (e.g. `http://corp-proxy:8080`) |

Explicit constructor args win over env vars:

```python
client = Client(api_key="...", base_url="https://eolaswork.your-co.com",
                timeout=120.0, max_retries=5)
```

### Running behind a corporate or notebook-environment proxy

If your environment has `HTTPS_PROXY` / `HTTP_PROXY` set globally (common
on Kaggle, Colab, corporate notebooks, VPN'd workstations) and the proxy
blocks `eolaswork.com` with a `403 Forbidden`, pass `trust_env=False` to
bypass it for SDK calls only:

```python
client = Client(api_key="nxa_...", trust_env=False)
```

Or point at a specific proxy:

```python
client = Client(api_key="nxa_...", proxy="http://corp-proxy:8080")
```

## Resource surface

| Resource | What it does |
|---|---|
| `client.account` | `whoami`, `instructions`, `preferences`, `artifacts` |
| `client.api_keys` | list / create / revoke programmatic keys |
| `client.tasks` | conversations CRUD + `send_message` |
| `client.runs` | create / retrieve / list / cancel / `wait` / `stream` / approve / deny |
| `client.files` | upload / list / download / delete / `to_pdf` |
| `client.roles` | catalogue + file content (read-only) |
| `client.teams` | catalogue + file content (read-only) |
| `client.skills` | catalogue + file content (read-only) |
| `client.models` | LLM model catalogue + providers |
| `client.followups` | cross-conversation action items |
| `client.memory` | user-level KV memory |

Async variants share the exact same surface on `AsyncClient` -- every method is awaitable.

## License

MIT.
