Metadata-Version: 2.4
Name: rbtrace
Version: 1.2.1
Summary: Self-serve ReasonBlocks dashboard capture setup for OpenAI, Anthropic, Gemini and Bedrock, with safe migration and local verification.
Author: ReasonBlocks
License: Proprietary
Project-URL: Documentation, https://docs.reasonblocks.com
Project-URL: Homepage, https://reasonblocks.com
Keywords: llm,agents,observability,tracing,anthropic,openai
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# rbtrace

Connect Python agents to the [ReasonBlocks](https://reasonblocks.com) dashboard.
Python 3.10+, no required dependencies.

The package provides a setup CLI and small Python helpers. It works with the
Python client library your application already uses: OpenAI, Anthropic,
google-genai (Gemini API) or boto3 (Bedrock Runtime).

## Set up with your coding agent

Give your coding agent the setup guide after publishing the matching package and documentation:

```text
Read https://docs.reasonblocks.com/agent-setup.md and integrate ReasonBlocks into this project.
```

Add `rbtrace==1.2.1` with your project's existing package manager, then generate the
connection using the exact source URL copied from **Data**:

```bash
python -m rbtrace init --capture-url "$REASONBLOCKS_CAPTURE_URL" --provider openai --json
```

Use `--provider anthropic` for Anthropic Messages, `--provider gemini` for the Gemini
API or `--provider bedrock` for Bedrock Runtime (see Gemini and Bedrock below). Add `--dry-run` to inspect the
planned files. Repeating `init` preserves identical files and refuses to overwrite
customized files. It writes `.reasonblocks/config.json`, `.reasonblocks/SETUP.md`
and `reasonblocks_setup.py`; your coding agent connects the helper to the application.

Choose an importable helper directory with `--path`. For a packaged application,
this may be `--path src/my_agent`, with `from my_agent import reasonblocks_setup`.
Include the adjacent `.reasonblocks/config.json` in package data or your deployment
image. Test the actual launch command outside the source directory.

Set `REASONBLOCKS_CAPTURE_KEY` in the application's secret environment (the existing
`RB_CAPTURE_KEY` name is also accepted). Keep your existing provider API key. The
capture key is read at runtime and never written into generated files.

For OpenAI and Anthropic the generated client options set `max_retries=0`, and for
Gemini they limit google-genai's retry policy to one attempt. This prevents an SDK
from silently repeating a paid request after a timeout. Your application can
explicitly change that option in the returned dictionary if it has its own
reconciliation policy. boto3 has no retry option `client_kwargs()` can return (its
policy comes from `config=`, `AWS_MAX_ATTEMPTS` or the AWS config file), so for
Bedrock pass it yourself, as shown under Gemini and Bedrock below. Keep existing provider credentials; the capture key is a separate,
source-scoped key, not a normal ReasonBlocks organization API key.

```python
from openai import OpenAI
import reasonblocks_setup

client = OpenAI(**reasonblocks_setup.client_kwargs())

# Once per task:
headers = reasonblocks_setup.run_headers()
# Reuse headers on EVERY model call in this task:
response = client.chat.completions.create(
    model=model,
    messages=messages,
    extra_headers=headers,
)
```

Basic capture needs no training sandbox or snapshot. The supported model APIs are
OpenAI Chat Completions, Anthropic Messages, Gemini `generateContent` and
`streamGenerateContent`, and Bedrock `Converse` and `ConverseStream` (plus
`InvokeModel` and `InvokeModelWithResponseStream` with an Anthropic Messages body). Keep executing tools in your existing
application and carrying the conversation forward as before.

The same options and per-task headers work with `AsyncOpenAI` and `AsyncAnthropic`.
For concurrent jobs, create a fresh header dictionary inside each job and reuse
only that dictionary throughout its tool loop. Streaming calls still receive
`extra_headers=headers`; consume the complete stream before checking collection.
Importing the generated helper installs request labeling for the configured capture
host, including current SDKs that use `httpx2`. Each run receives `x-rb-run` and
incrementing `x-rb-seq` headers. Installation sends no requests and does not change
model payloads, credentials, or retry settings. `RBTRACE_DISABLE=1` disables labeling
at startup; `doctor` reports that condition. You do not need to patch a transport
yourself. Keep explicit task boundaries: unscoped tasks share a process-wide run.

For older integrations, `rbtrace.client.install()` and `with rbtrace.client.run():`
remain available. They only label requests; they do not configure the capture URL
or capture authentication. Unscoped jobs share a process-wide default run. Use
the explicit helper above for new dashboard integrations. Basic capture groups
by run ID; successful local setup alone does not prove complete sequence capture.

In 1.1.1, `RBTRACE_HOSTS=capture.example.com` authorizes only that exact host.
Use a leading-dot entry such as `.example.com` to include subdomains explicitly;
use `example.com,.example.com` for both the apex and its subdomains. The generated
helper adds only its configured capture host. Existing `*` and leading-dot choices
remain unchanged.

```bash
python -m rbtrace doctor --json
```

Run `doctor` in the application's Python environment with the same `--path` used
for initialization. It checks local configuration, the selected provider library
capture-key presence, and whether the selected SDK transport can be labeled. It
makes no network requests, verifies no remote key or
captures, and explicitly reports cloud authentication and application wiring as
unverified. Running a CLI with `uvx` does not install the dependency in your app.

## Gemini and Bedrock

The generated `.reasonblocks/SETUP.md` gives the steps for the provider you chose.
For Gemini, the helper's options go into `http_options`, and the per-task headers
ride each call's own `http_options` (google-genai merges them with the client's):

```python
from google import genai
import reasonblocks_setup

client = genai.Client(**reasonblocks_setup.client_kwargs())

headers = reasonblocks_setup.run_headers()          # once per task
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=prompt,
    config={"http_options": {"headers": headers}},  # on EVERY call in the task
)
```

Use a Gemini API key. The options pin `vertexai=False`, so `GOOGLE_GENAI_USE_VERTEXAI`
cannot switch the client to Vertex AI, which dashboard capture does not support; do not
also pass `vertexai` yourself. If
you already pass `http_options`, merge ours into yours, merging `headers` one level
deeper so both your headers and `x-reasonblocks-key` are kept. With aiohttp
installed, google-genai's async client resends a request once by itself when the
connection drops before a response; reconcile such a call before retrying it.

For Bedrock, boto3 has no constructor option for an extra header and no per-call
header argument, so the helper registers the connection key on the client and
scopes each task:

```python
import boto3
from botocore.config import Config
import reasonblocks_setup

client = boto3.client("bedrock-runtime", region_name="us-east-1",
                      config=Config(retries={"total_max_attempts": 1}),  # no silent paid retries
                      **reasonblocks_setup.client_kwargs())
if not reasonblocks_setup.capture(client):           # not assert: python -O removes it
    raise RuntimeError("ReasonBlocks capture is not registered on this client")

with reasonblocks_setup.task():                      # once per task
    response = client.converse(modelId=model_id, messages=messages)
```

`capture()` raises if a bedrock-runtime client was not built with `client_kwargs()`,
rather than let calls go straight to AWS uncaptured (and returns False for anything
else, where there is nothing to register). A task follows the current thread or
asyncio task, and worker threads do not reliably inherit it: inside `with task():`,
always submit `reasonblocks_setup.in_task(fn)` to a thread pool instead of `fn`, or use
`asyncio.to_thread`. A worker call sent while a task is open but without it is logged
once as a warning. Keep one task per thread or asyncio task: two scopes held open
across `yield` in interleaving generators label every call with the innermost.

Bedrock needs a Bedrock API key (`AWS_BEARER_TOKEN_BEDROCK`). SigV4 access keys
cannot pass through the dashboard connection: their signature covers the host and path
the request is sent to, the capture URL, so it cannot verify at Bedrock. Use the region in your source's URL from **Data**.

## Move an earlier generated connection to the dashboard

Create a source in **Data**, obtain its capture URL and key, then run:

```bash
python -m rbtrace migrate --capture-url "$REASONBLOCKS_CAPTURE_URL" --provider anthropic --path . --json
```

Add `--dry-run` to preview. Migration backs up the original generated files and
replaces them with dashboard configuration and helpers. It refuses to overwrite
a customized helper. Exact generated 1.1.0 files are recognized and backed up
before upgrading their import-time labeling, and so are the Gemini and Bedrock files
1.2.0 generated, which described an OpenAI client; `doctor` reports those until they
are migrated. Repeating a completed migration makes
no changes.

Your coding agent must use `client_kwargs()` at client construction and
`run_headers()` once per task, passed on every model call. For Bedrock, it adds
`capture(client)` after construction and wraps each task in `with task():` instead;
the migrated Bedrock helper keeps `run_headers()` only so existing code still runs. Existing explicit
`rbtrace.client.run()` scopes may be retained. Remove obsolete
`reasonblocks_setup.install()` calls; importing the helper installs labeling. Remove old gateway base-URL settings from
application/deployment configuration and restart the application. Migration of
configuration alone does not change existing application call sites.

Use the application's existing supported provider. An application using a different
provider or OpenAI Responses needs an explicitly chosen compatible integration;
the migration command does not switch its model API automatically.

## Training later

Full-agent training lets a smaller model try new actions through your agent's tools.
It needs a resettable sandbox: for example, test support tickets and a test database
that can be restored for every attempt, plus a checker that decides whether the
task succeeded. The sandbox can be hosted wherever your deployment supports; it
must expose the application's actual tool behavior.

Once that environment exists, attach its real starting snapshot to each task:

```python
headers = reasonblocks_setup.run_headers(snapshot_id=starting_snapshot_id)
# Bedrock: with reasonblocks_setup.task(snapshot_id=starting_snapshot_id):
```

This ID refers to a saved state; the helper does not create it. Ordinary capture
alone does not preserve tool/database state for later replay. See
[full-agent training](https://docs.reasonblocks.com/full-agent-training) for the
sandbox connection and preparation steps.

## Reusable agent skill

After documentation publication:

```bash
npx skills add https://docs.reasonblocks.com
```

Select `reasonblocks-setup`. The [setup guide](https://docs.reasonblocks.com/agent-setup)
covers task boundaries, async clients and deployment layout. Python helpers must
be wired where requests actually occur; they do not reach JavaScript clients or
model calls made by a separate child process.
