> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zespan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Capture fields

> Which data each check reads, which switch controls it, how large it can be, and which integrations send it. Readiness shows what could run, not how good your agent is.

Zespan's trace checks read what your SDK recorded: the final answer, the conversation, the system instructions, the tool definitions, and what each tool was asked and returned. A check never guesses. When an input is missing, the check reports that it **could not run** and names the input, instead of passing.

This page lists each input, the switch that controls it, its size limit, and which integrations send it. It does not say how well your agent works: a trace where every check could run can still have problems, and one where few could run is a gap in what was recorded, not a verdict on the agent.

## Capture v2

Capture v2 is **off by default**. It records fields that earlier SDK versions dropped or recorded in a form the checks could not read. It changes nothing until you turn it on, and with it off every event is exactly what it was.

> [tab] Python
>
> ```python theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
> import zespan
>
> zespan.init(api_key="zsp_your_api_key_here", capture_v2=True)
> ```
>
> Or set `ZESPAN_CAPTURE_V2=1`. `ZESPAN_CAPTURE_V2=0` (or `false`, `off`) always turns it off, whatever the option says.

> [tab] TypeScript
>
> ```ts theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
> import { init } from "@zespan/sdk";
>
> init({ apiKey: "zsp_your_api_key_here", captureV2: true });
> ```
>
> Or set `ZESPAN_CAPTURE_V2=1`. `ZESPAN_CAPTURE_V2=0` (or `false`, `off`) always turns it off, whatever the option says.

Two sub-options only matter when v2 is on, and both default to on: `capture_tool_definitions` / `captureToolDefinitions` and `capture_agent_io` / `captureAgentIO`.

Capture v2 does not change what you are allowed to store. **Prompt storage** (`store_prompts` / `storePrompts`) and **tool input and output storage** (`store_tool_io` / `storeToolIO`), and the matching project settings, still decide what is kept, and redaction stays always on. Every new field goes through the same redaction as stored prompts. See [PII redaction](https://docs.zespan.com/sdk/pii-redaction.md).

## What is recorded

| Input | Controlled by | Limit | Notes |
| - | - | - | - |
| Final answer text | Prompt storage | Not limited beyond the usual text cap | The model span carries it; with v2 the agent span also carries the last text the agent produced (8,192 characters) |
| Conversation messages | Prompt storage | 32,768 characters per model call | Recorded as a structured message list with roles. When it does not fit, the first user message and the most recent messages are kept |
| System instructions | Prompt storage | 64 KB | Stored once per project and version |
| Output schema | Prompt storage | 8,000 characters | The structured-output contract of the request. A larger schema is recorded as names and types only |
| Tool definitions | Tool input and output storage | 64 tools, 8,000 characters in all, descriptions 500 characters, one schema 2,048 characters | `default`, `example` and `const` values are removed from schemas, and an `enum` is kept only when every value is short and not secret-shaped. A tool with no declaration (a built-in search tool, for example) is recorded by name |
| Requested tool calls | Tool input and output storage | 50 calls, 4,096 characters each | What the model asked for, with the call id, so a request can be matched to its execution, and a request that never ran can still be seen |
| Tool arguments | Tool input and output storage | 10,240 characters | Keyed secrets are replaced before anything is cut |
| Tool results | Tool input and output storage | 10,240 characters | Recorded as JSON. A result that is empty (`null`, `[]`, `{}` or nothing) is kept and marked empty, not dropped. A result cut at the limit is marked as cut |
| Tool names | Always | 50 names | Names carry no content, so they are kept even when tool storage is off |

### Image input metadata

A provider that rejects a call for an invalid image usually says only "invalid image". With `capture_image_meta` / `captureImageMeta` (or `ZESPAN_CAPTURE_IMAGE_META=1`; `=0` always turns it off) on top of capture v2, the SDK records **metadata only** for each image part of a model request, on the model call, including a call that failed. It never records the image bytes, a full URL, a query string or a file name, and it is off by default.

| Field | Meaning |
| - | - |
| Kind | Inline bytes or base64, data URL, remote URL, or a file reference |
| Declared type and type read from the first bytes | PNG, JPEG, GIF, WebP, HEIC, AVIF, BMP, TIFF or PDF; a mismatch is what a wrong content type looks like |
| Size | Bytes, from the text length for base64 |
| Base64 check | Valid, wrapped in line breaks, bad characters, bad padding or bad length |
| Width and height | Read from the header for PNG, JPEG, GIF and WebP only |
| URL | Scheme and host only. Whether a pre-signed link carries an expiry, whether it had expired, and how long it had left |
| Hash | SHA-256, only for images up to 256 KiB |
| Source | The tool call that produced the image, when the image came from a tool result |

At most 8 images are described per call (the count of all is kept). When the data for a call is too large it is dropped as a whole and marked, never partly kept. With prompt storage off the host and the hash are left out. It is sent by every wrapper and integration that records model calls (OpenAI, Anthropic, Google GenAI and ADK, Mistral, Groq, Cohere, Bedrock, LiteLLM, LangChain, and in TypeScript Vercel AI and LlamaIndex); also the OpenAI Responses API (`responses.create`, in both SDKs, streamed or not), Google GenAI chat sessions and streamed calls that the provider rejects before the first chunk, and in Python Haystack and Semantic Kernel. Haystack needs its content tracing on (`HAYSTACK_CONTENT_TRACING_ENABLED=true`), because that is how the component input reaches Zespan; for Semantic Kernel the images are read from a `ChatHistory` passed as an argument of a prompt function, not from images written inside the prompt template text. Zespan does not ship a TypeScript Haystack or Semantic Kernel integration.

### Markers

Each recorded field comes with a small marker saying how it was captured: present, absent (the agent has no instructions, the last turn was only tool calls), cut, off, or not available from this integration. A marker holds fixed words and numbers, never content, so it is sent even when prompt or tool storage is off. It is what lets a check say **absent** or **not available from this integration** instead of **not captured**.

### Why a check could not run

| Reason | Meaning |
| - | - |
| Not captured | Nothing says why: an older SDK, or an integration that does not send it |
| Capture is off | Prompt or tool input and output storage is off for the project |
| Cleared by retention | The stored content is past the retention period |
| Not available from this integration | The framework does not expose the field |
| Captured but empty | The field was recorded and is genuinely empty (no instructions set, a turn of tool calls only) |
| Cut at the storage limit | The value is present but cut, so a claim that something is missing from it is not safe |
| Could not be read | The value was recorded in a form that cannot be read, such as a text copy of an object |
| Does not apply | The check is not relevant to this trace (an embedding-only trace, a single failed model call) |
| No tool mapping | The check needs to know which of your tools does what, and nobody has confirmed a mapping |

A check that is **captured but empty** or **does not apply** is not counted against readiness.

## What capture can and cannot unlock

Capture changes what the checks can read. It does not unlock everything:

* **Checks that need a confirmed tool mapping** (for example, checks of a customer-data pack) run only after a person confirms which tools do what. Upgrading the SDK does not enable them.
* **The end-user feedback check** needs your app to tag traces with feedback.
* **Session checks** need a session id on each trace.
* A trace where the model call failed, or that only holds embedding or image calls, has no answer to check. That is **does not apply**, not a gap.

## Integrations

| Integration | Sent with capture v2 |
| - | - |
| Google ADK (callback handler, Python and TypeScript) | Tool results as JSON, tool definitions, requested tool calls with ids, structured messages, system instructions, output schema, agent input and output text, grounding references, tool error codes |
| Google GenAI (Python, TypeScript, and the older Google SDKs) | Structured messages, tool definitions, requested calls, output schema, error codes, grounding references |
| LangChain and LangGraph (Python and TypeScript) | Tool results as JSON (a `ToolMessage` is unwrapped), the tool call id, tool definitions |
| LlamaIndex, OpenAI Agents, Claude Agent SDK (Python and TypeScript), Semantic Kernel (Python), Vercel AI (TypeScript), `trace_tool` / `traceTool` | Tool results as JSON |
| OpenAI, Anthropic, Mistral, Cohere, Groq, Bedrock, LiteLLM, OpenRouter wrappers | The marker only; they already send tool definitions and requested calls |
| OpenTelemetry (`OTEL_CAPTURE_V2` on a self-hosted deployment) | Tool definitions from `gen_ai.tool.definitions` and OpenInference tool schemas; Google ADK native spans' request and response; the real tool call id; `error.type` as the error code |

Not covered yet: Python and TypeScript CrewAI and AutoGen tool results, TypeScript Semantic Kernel, and streamed Google GenAI calls.

> [!NOTE]
>
> `wrap_adk_agent` (Python) is deprecated and warns once. It patches an agent method that current ADK agents do not have, and it never sent the instructions. Use `ZespanADKCallbackHandler`.

## Readiness

When readiness is enabled for your deployment (self-hosted: `CAPTURE_READINESS=on`), Zespan can tell you, per trace and per project, which checks could not run and why:

* `GET /v1/projects/{id}/traces/{traceId}/functional/unchecked` lists the checks that could not run on one trace and the input each lacked.
* `GET /v1/projects/{id}/functional/readiness?days=7` returns the share of checks that could run over the last 1 to 7 days (**readiness**, not a quality score), the same share leaving out the inputs only a person can supply, the inputs that cost the most with what to do about each, and the figure per agent. It holds counts and fixed wording only, never content, and answers `404` while readiness is not enabled.

## Self-hosted deployments

Some of the server-side reading described on this page (storing the output schema, reading the OpenTelemetry tool definitions above, filling in tool names and error codes from data a span already carries, and reading older tool results stored as Python literals as structure) is off by default on a self-hosted deployment and turned on with server settings. Contact us for the settings that match your version.

## Next steps

* [Google ADK](https://docs.zespan.com/sdk/integrations/google-adk.md) and [Google GenAI](https://docs.zespan.com/sdk/integrations/google-genai.md) — what each sends
* [PII redaction](https://docs.zespan.com/sdk/pii-redaction.md) — how every field is redacted
* [Silent-failure coverage](https://docs.zespan.com/reference/silent-failure-coverage.md) — what the checks cover
* [Findings](https://docs.zespan.com/dashboard/findings.md) — how findings and "could not run" reasons appear


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.