Metadata-Version: 2.4
Name: onetrace-auto
Version: 0.7.0
Summary: Zero-configuration recording for onetrace: a run folder from a library's calls, with nothing added to the app
Author-email: Shamik Saha <shamik.saha.rcciit@gmail.com>
License-Expression: Apache-2.0
Project-URL: Issues, https://github.com/shamiksaharcciit-oss/onetrace-issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: onetrace==0.7.0

# onetrace-auto

Zero-configuration recording for [onetrace](https://pypi.org/project/onetrace/): run an app as
you run it today, with one thing added at the edge, and get a run folder with a receipt per hooked
library call. Released with onetrace, at the same version, and pinned to it.

## Install

```
pip install onetrace-auto
```

This installs one `.pth` line into the environment. It runs at every interpreter start there, and
with `ONETRACE_AUTO` unset it reads two environment variables and imports nothing. The `onetrace`
package alone installs no `.pth` line.

## Use

```
onetrace-run python app.py
```

or set the variable yourself:

```
ONETRACE_AUTO=1 python app.py
```

Only the value `1` turns recording on, and `ONETRACE_DISABLE=1` turns it off whatever else is set.
Each Python process records its own run, under `ONETRACE_RUNS` (default `./runs`), opened at its
first hooked call: a process that makes none leaves no folder.

An auto-recorded run is complete only with respect to the libraries hooked, at the versions its
manifest lists in `auto.hooks`. A step in your own code is recorded only where a decorator names
it. A run folder may contain sensitive data: by default it holds digests only.

## Hooked libraries

| library | versions | stage | what a step records |
|---|---|---|---|
| openai | `>=1.40,<4` | `openai.chat.completions.create`, `openai.responses.create`, `openai.embeddings.create`, `openai.completions.create` | `create` on each, on `OpenAI` and `AsyncOpenAI`; a stage is declared only where the installed version has its resource (1.40 has no `responses`) |
| requests | `>=2.28,<3` | `requests.send` | `Session.send`, so `requests.get(...)`, every session method and a prepared request sent by hand |
| httpx | `>=0.24,<1` | `httpx.send` | `Client.send` and `AsyncClient.send`, so every request method |

An HTTP step records the request body as its input `request`, and two outputs: `status`, the JSON
object `{"status": "<code>"}`, and `response`, the body's bytes. A requests call that followed
redirects is one step: its `status` is the final response's, with the number of hops,
`{"redirects": "<n>", "status": "<code>"}`, and its `response` is the final body. A requests text body is
digested as the installed urllib3 sends it: ISO-8859-1 below urllib3 2, UTF-8 from 2. Where
ISO-8859-1 cannot encode it, the step records no `request` input and says why. A streamed response's body is not
read, so the step records `status` alone and says so in the constant `onetrace.http.body`. A
streamed request body is not read either: the step has no `request` input and says so in
`onetrace.http.request`. The target is the host, the method, the path's sha256 and the query's
parameter names; no query value and no user info is recorded. An error records its class, never its
message, since an HTTP library's message can hold the URL.

A model call records its request body as `request`, the response's `model_dump()` as `response`,
and a model-call record, `model_call.json`, by the hosted adapter's rules. The record's
`credential` (only whether a key is set, never the key) and the step's host come from the client's
own `post` method, read while the call runs. A streamed call returns the library's stream, wrapped:
the step ends when the stream does, and a stream left before its end is an error. Usage is in
`response`, not in the record. An error records its class and its message, with every URL's user
info and query values removed.

What a model call does **not** record:
- **where openai was imported before onetrace-auto's boot,** a call on a client made then records
  no credential, no host and no model-call record. The step is recorded, and the constant
  `onetrace.model_call` says `not written: the hook did not see the client's request`. With
  `onetrace-run`, or `ONETRACE_AUTO=1` set before the interpreter starts, boot comes first;
- **an embeddings call** has no record format in this release: it records `request` and
  `response`, and the constant says so;
- **under openai 3.x, the client's HTTP layer** (`httpx2`) is not recorded by the httpx hook. The
  model step itself is recorded.

## Settings

- `ONETRACE_AUTO_KEEP=outputs` keeps the output files; `inputs` keeps each request body of up to
  4096 bytes (a larger one is named, not kept). Both: `outputs,inputs`.
- `ONETRACE_AUTO_MAX_RUN_BYTES=<bytes>` gives the process's run a store bound, in decimal digits: the
  receipts and kept outputs count toward it, the manifest does not. The step that reaches it is
  recorded as a gap, the run declares the boundary `store bound reached` naming that step and
  closes, and every later hooked call goes ahead unrecorded. Unset or empty: no bound. A value that
  is not a whole decimal number, or is below the smallest the run's receipts allow, opens no run,
  and the process says why once on stderr. It is read once, when the run opens; a decorated
  `@ot.run` does not read it.
- `ONETRACE_AUTO_HTTP_PATH=plain` records the path itself in place of its digest.
- `ONETRACE_AUTO_KEEP_QUERY=name,...` records the named query parameters' values as configuration.
