# OpenAI Agents SDK

The Agents SDK reads `OPENAI_API_KEY` and `OPENAI_BASE_URL` from the environment,
which makes both the zero-code shape and the proxy shape configuration-only. The
one thing to know about is the tracing exporter.

> **Note:** **Start here if seekrit is new:** [three commands](/docs/guides/frameworks#get-running-in-five-minutes) put the keys in an environment, mint a token bound to it, and export `SEEKRIT_TOKEN`. A token reads [everything in its environment](/docs/guides/frameworks#which-secrets-does-the-agent-get), so there is no per-key or per-framework setup to do before any of the below.

## 1. Wrap the process

```bash
seekrit run -- python agent.py
```

```python
from agents import Agent, Runner

agent = Agent(name="Assistant", instructions="You are a helpful assistant")
result = Runner.run_sync(agent, "Write a haiku about recursion.")
print(result.final_output)
```

No seekrit-specific code at all — the key arrives in the environment the SDK
already reads.

## 2. Resolve in code

```python
import seekrit
from agents import set_default_openai_key

set_default_openai_key(seekrit.Client().get("OPENAI_API_KEY"))
```

Set it before the first model call. For a fully custom client — a different
endpoint, an org header, a shared `httpx` client:

```python
import seekrit
from openai import AsyncOpenAI
from agents import set_default_openai_client

secrets = seekrit.Client().resolve()
set_default_openai_client(AsyncOpenAI(api_key=secrets["OPENAI_API_KEY"]))
```

Pass either `openai_client` **or** `api_key`/`base_url`, never both — combining
them raises `UserError` rather than silently ignoring one.

## 3. Never hold the key

Environment only, no source change:

```bash
export OPENAI_BASE_URL=http://127.0.0.1:8080/openai/v1
export OPENAI_API_KEY='{{seekrit:OPENAI_API_KEY}}'
```

```toml
# seekrit-proxy.toml
listen = "127.0.0.1:8080"

[[route]]
prefix = "/openai"
upstream = "https://api.openai.com"
allow = ["OPENAI_API_KEY"]
methods = ["POST"]
paths = ["/v1/responses", "/v1/chat/completions"]
```

### Without running the proxy

`set_default_openai_client` takes a client, and a client takes a transport:

```python
import httpx
from openai import AsyncOpenAI
from agents import set_default_openai_client
from seekrit.transport import AsyncSeekritTransport

set_default_openai_client(
    AsyncOpenAI(
        api_key="{{seekrit:OPENAI_API_KEY}}",
        http_client=httpx.AsyncClient(
            transport=AsyncSeekritTransport(allow={"api.openai.com": ["OPENAI_API_KEY"]}),
        ),
    )
)
```

Weaker than the proxy, since it runs in your process:
[in-process injection](/docs/guides/agent-proxy/in-process) sets out the
trade-off.

## Gotchas

- **Tracing uses the same credential, to a different path.** The SDK exports
  traces to OpenAI by default with your API key. Behind the proxy that means
  trace uploads carry the placeholder too — so either allow the trace ingest
  path in your route, give tracing its own credential with
  `set_tracing_export_api_key(...)`, or turn it off with
  `set_tracing_disabled(True)`. If traces vanish the moment you add the proxy,
  this is why.
- **`OPENAI_WEBSOCKET_BASE_URL` is separate.** Realtime/websocket transport does
  not follow `OPENAI_BASE_URL`. The proxy substitutes on HTTP requests, so
  websocket traffic needs its own decision — usually: don't put a placeholder in
  that path.
- **Handoffs share the process.** Every agent in a handoff chain sees the same
  environment. Per-agent credential separation needs the proxy's session
  tickets, not a second env var.
