Metadata-Version: 2.5
Name: niyoos
Version: 0.1.0
Summary: Beta — run labelling for the Niyoos proxy: wraps your own OpenAI client so every call carries its run id, step and parent run.
Project-URL: Homepage, https://niyoos.com
Author-email: Niyoos <support@niyoos.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agents,governance,llm,niyoos,observability,openai,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
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 :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.23
Provides-Extra: dev
Requires-Dist: mypy>=1.5; extra == 'dev'
Requires-Dist: openai>=1.0; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == 'openai'
Provides-Extra: test
Requires-Dist: openai>=1.0; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# niyoos — Python SDK

**[Niyoos](https://niyoos.com)** is the model gateway for your AI agents: every LLM call they make goes through
the Niyoos proxy, where it is recorded, priced and governed. This SDK labels each call with the run it
belongs to, so you can see what an agent did, step by step.

> **Beta — the API may change before 1.0.**

Labels every LLM call your agent makes through the Niyoos proxy with the run it belongs to, its
step, and the run that spawned it. Your agent keeps its own `openai` client.

## Install

```sh
pip install "niyoos[openai]"
```

## Quickstart

Create an agent in the [Niyoos dashboard](https://niyoos.com), copy its agent key, and wrap your own
OpenAI client with it:

```python
import niyoos
from openai import OpenAI

client = niyoos.wrap(OpenAI(api_key=NIYOOS_AGENT_KEY))  # points at https://api.niyoos.com/proxy/v1

with niyoos.run():                       # new run: a UUIDv7 id, steps counted 1, 2, 3 …
    client.chat.completions.create(model="gpt-4o", messages=[...])
    with niyoos.run():                   # a sub-agent: its own run, parent linked automatically
        client.chat.completions.create(model="gpt-4o", messages=[...])
    pool.submit(niyoos.bind(tool_call))  # thread pools need bind() to stay in the run
```

`@niyoos.run()` works as a decorator, and `async with niyoos.run():` works for async code.
`niyoos.run(run_id="order-1234", parent_run_id=parent_id)` continues a run, or links a sub-agent
that runs in another process; pass it `niyoos.current_run_id()` from the parent.

## What goes on the wire

| Header | Value |
|---|---|
| `x-niyoos-run-id` | the run id, 8–64 of `A-Z a-z 0-9 _ -` |
| `x-niyoos-step` | 1, 2, 3 … within the run; a retry repeats its step |
| `x-niyoos-parent-run-id` | the parent run, for a nested run |
| `x-niyoos-client` | `sdk-python`, on every request |
| `User-Agent` | the openai library's own, with `niyoos-python/0.1.0` appended |

Outside a run, none of the three run headers is sent. **Run headers also work without this SDK:**
any HTTP client can send them; the SDK only mints the ids, counts steps and links parents for you.

## Behaviour you should know

- **Labels are advisory.** Every policy (kill switch, rate and cost limits) is enforced by the
  server whether or not a call is labelled. If the SDK ever fails to build a label, the call goes
  out unlabelled, with one warning, and is not otherwise affected.
- `wrap()` changes the client you pass and returns it. It sets the Niyoos base URL only when the
  client still points at the OpenAI default. A `base_url` you set yourself is left alone.
- `ThreadPoolExecutor.submit` and `loop.run_in_executor` do not carry the run. Wrap the function
  with `niyoos.bind(fn)`. (`asyncio.gather`, `create_task` and `asyncio.to_thread` do carry it.)
- A generator that makes calls belongs to whichever run is open when it is *resumed*.
- Retries are recognised from the openai library's `x-stainless-retry-count` header. A client
  that does not send it counts each retry as a new step.
- The request body is never modified.
- For other libraries, pass `niyoos.httpx_client()` / `niyoos.async_httpx_client()` as their HTTP
  client, e.g. `Anthropic(http_client=niyoos.httpx_client(), base_url="https://api.niyoos.com/proxy")`.
  There are no dedicated Anthropic or LangChain adapters in v0.1.

Python 3.9 or later. The only required dependency is `httpx`; `pip install niyoos[openai]` adds
the openai library (`>=1.0`).

## Licence

Apache-2.0. Questions: support@niyoos.com · https://niyoos.com
