Skip to content

Recording APIs

Agents talk to LLM providers and third-party services over HTTP. AgentTape captures those calls three ways — pick the one that fits.


Three interception layers

flowchart TD
    Call[Your code makes a call] --> Q{Is there a<br/>dedicated adapter?}
    Q -->|"yes (e.g. OpenAI)"| A[SDK adapter<br/>rich semantics, rehydrated objects]
    Q -->|no, but uses httpx/requests| B[Raw HTTP fallback<br/>always on]
    Q -->|"want a clean named boundary"| C["@agenttape.tool wrapper"]
Layer Captures When it applies
SDK adapter Model, messages, token usage; rehydrates into real SDK objects The SDK has a dedicated adapter (OpenAI today)
Raw HTTP fallback Method, URL, headers, body, status Any call through httpx or requests
@agenttape.tool Whatever your function returns You want a semantic, named boundary

Layer 1 — Dedicated SDK adapters

If the matching extra is installed, AgentTape intercepts the SDK automatically. No code changes — just wrap your code in a session.

import agenttape
from openai import OpenAI

with agenttape.use_cassette("api_test", mode="record"):
    client = OpenAI()
    client.chat.completions.create(
        model="gpt-5.5",
        messages=[{"role": "user", "content": "Hello"}],
    )

The OpenAI adapter covers chat.completions.create, responses.create, and embeddings.create (sync and async). It records token usage, and on replay rehydrates the recorded data back into a real ChatCompletion object — so resp.choices[0].message.content works offline, even without openai installed.

Prefer adapters when one exists

A dedicated adapter captures semantic metadata (model, usage) that a generic HTTP capture would miss, and gives you back real SDK objects. Install it with pip install "agenttape[openai]".


Layer 2 — The raw HTTP fallback (always on)

Any SDK built on httpx or requests is captured automatically, even with no dedicated adapter. These fallback adapters are always active whenever those libraries are importable — you don't install or enable anything.

import agenttape
import httpx

with agenttape.use_cassette("github", mode="record"):
    r = httpx.get("https://api.github.com/users/octocat")
    print(r.json()["name"])   # replays offline next time

How HTTP matching works:

  • The request is matched on method + URL + body + non-volatile headers.
  • Secret and volatile headers (Authorization, Cookie, User-Agent, Date, request IDs, …) are dropped from the recording — so they neither leak to disk nor destabilize matching.
  • JSON and form bodies are captured structurally (not as one opaque blob), so redaction can see nested secrets and matching survives key reordering.

Why some response headers disappear

The recorded body is the decoded payload. Transport headers describing the wire encoding (Content-Encoding, Content-Length, Transfer-Encoding) are dropped from the recorded response — keeping them would make the client try to gunzip an already-decompressed body on replay.


Layer 3 — Wrap it as a tool

When you want a clean, named, semantic boundary — or you're calling something that isn't plain HTTP — wrap the call in a function and decorate it.

import agenttape
import requests

@agenttape.tool
def get_github_user(username: str) -> dict:
    resp = requests.get(f"https://api.github.com/users/{username}")
    resp.raise_for_status()
    return resp.json()

During recording the request runs for real. During replay, get_github_user returns the saved dict and the network is never touched. The cassette shows a tidy tool: get_github_user interaction instead of a raw HTTP entry. See Tools.


Which layer should I use?

Rule of thumb

  • LLM provider with an adapter → let the adapter handle it (install the extra).
  • Some other REST API your agent hits directly → the raw HTTP fallback already captures it; do nothing.
  • You want a readable, named boundary or domain-level mocking → wrap it with @agenttape.tool.

FAQ

Do I need agenttape[openai] if I only use httpx?

No. The httpx/requests fallback captures the traffic regardless. But for OpenAI specifically, the dedicated adapter gives you token usage and real SDK objects, so it's worth installing.

The same OpenAI call is captured by both the adapter and httpx — do I get duplicate entries?

No. The engine has a re-entrancy guard: while the OpenAI adapter's call executes, the nested httpx call passes through instead of being recorded again. The outermost boundary is the one captured.

Can I record an API that uses raw sockets / a custom transport?

The HTTP fallback only covers httpx and requests. For anything else, wrap the call with @agenttape.tool, or write a custom adapter.


Summary

  • Three layers: dedicated SDK adapters, the always-on httpx/requests fallback, and @agenttape.tool.
  • Adapters capture rich semantics and rehydrate SDK objects; install the extra to use them.
  • The raw HTTP fallback captures any httpx/requests call, dropping secret/volatile headers.
  • Wrap a call as a tool when you want a clean, named, domain-level boundary.

Next: Recording Databases →