# Event Schema

The SDK produces 8 event types, all prefixed with `[Agent]`. When `content_mode` is `"full"`, the server enrichment pipeline adds events per session, bringing the total to **10 event types** (8 SDK + 2 server-unique + 1 shared). See [constants.md](constants.md) for all property name constants.

## SDK Events

| Event | Method | Description |
|-------|--------|-------------|
| `[Agent] User Message` | `track_user_message()` | Session/trace/turn IDs, message content, agent IDs, implicit feedback (regeneration, edit), file attachments |
| `[Agent] AI Response` | `track_ai_message()` | Model, provider, latency, tokens (including reasoning), cost, finish reason, reasoning content, has-reasoning flag, system prompt, model config (temperature, top_p, max_output_tokens, is_streaming, prompt_id), copy signal |
| `[Agent] Tool Call` | `track_tool_call()` | Tool name, input/output, latency, success status |
| `[Agent] Embedding` | `track_embedding()` | Model, provider, latency, tokens, vector dimensions, cost |
| `[Agent] Span` | `track_span()` | Generic operation tracking (name, input/output state, latency, parent span hierarchy) |
| `[Agent] Session End` | `track_session_end()` | Explicit session close with optional enrichments, abandonment tracking |
| `[Agent] Session Enrichment` | `track_session_enrichment()` | Customer-provided session classifications. Distinct from server-side `[Agent] Session Evaluation`. |
| `[Agent] Score` | `score()` | Quality signal attached to a message or session (user feedback, automated evals, human annotations) |

## Server-Side Events (automatic)

| Event | Description |
|-------|-------------|
| `[Agent] Session Evaluation` | Session-level summary: outcome, turn count, flags (`has_task_failure`, `has_negative_feedback`), metadata |
| `[Agent] Topic Classification` | One event per configured topic model per session: `model_name`, `l1`, `l2`, `values` |
| `[Agent] Score` (reused) | One event per configured rubric per session, with `[Agent] Evaluation Source = "ai"` |

## Score Properties

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `[Agent] Score Name` | string | Yes | What's being scored: `"user-feedback"`, `"accuracy"`, `"helpfulness"`, `"toxicity"` |
| `[Agent] Score Value` | float | Yes | Numeric score. Binary: 1/0. Continuous: 0.0-1.0. Rating: 1-5. |
| `[Agent] Score Label` | string | No | Server-derived direction-neutral magnitude label (e.g., `"very_high"`, `"moderate"`). Set by enrichment pipeline based on Score Value. Customizable via taxonomy config. |
| `[Agent] Target ID` | string | Yes | The `message_id` or `session_id` being scored |
| `[Agent] Target Type` | string | Yes | `"message"` or `"session"` |
| `[Agent] Evaluation Source` | string | Yes | `"user"` (UI feedback), `"ai"` (LLM-as-judge), `"reviewer"` (human review) |
| `[Agent] Comment` | string | No | Optional text explanation. Respects `content_mode` privacy tiers. |
| `[Agent] Session ID` | string | No | Session context for linking |
| `[Agent] Agent ID` | string | No | Which agent the score relates to |
| `[Agent] Agent Version` | string | No | Version/revision of the agent code (e.g., `"v4.2"`, `"2025-02-11"`, git SHA) |

## Context Properties (all events)

These properties are set automatically by `BoundAgent` and propagated to every event. They enable segmentation and comparison across agent versions, environments, tenants, and experiment variants.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Agent ID` | string | Logical agent identifier (e.g., `"support-bot"`, `"researcher"`) |
| `[Agent] Agent Version` | string | Version of the agent code. Free-form string -- use semver (`"v4.2"`), dates (`"2025-02-11"`), git SHAs, or prompt revision IDs. Inherited by child agents. |
| `[Agent] Context` | JSON string | Arbitrary key-value pairs for segmentation. Serialized as JSON. Convention keys: `experiment_variant`, `feature_flags`, `prompt_revision`, `canary_group`, `deployment_region`. Inherited by child agents (merged -- child keys override parent keys). |
| `[Agent] Parent Agent ID` | string | ID of the parent agent (set automatically by `agent.child()`) |
| `[Agent] Customer Org ID` | string | Org ID of the end customer (multi-tenant platforms) |
| `[Agent] Env` | string | Environment tag (`"production"`, `"staging"`, `"development"`) |
| `[Agent] SDK Version` | string | SDK version (auto-detected from package metadata) |
| `[Agent] Runtime` | string | Always `"python"` |

## Cache & Model Tier Properties

Properties on the `[Agent] AI Response` event for semantic cache hits and model classification.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Was Cached` | boolean | Whether this response was a semantic cache hit (distinct from token-level prompt caching). Only set when `true`. |
| `[Agent] Model Tier` | string | Model tier classification (e.g., `"flagship"`, `"mid"`, `"small"`). Auto-inferred from model name if not provided. |

## Message Label Properties

Properties on `[Agent] User Message` and `[Agent] AI Response` events for structured content labeling.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Message Labels` | string[] | List of label strings attached to the message. |
| `[Agent] Message Label Map` | JSON string | Structured label map with categories and values, serialized as JSON. |

## Session Replay Linking

| Property | Type | Description |
|----------|------|-------------|
| `[Amplitude] Session Replay ID` | string | Links AI events to browser Session Replay recordings. Auto-computed from `device_id` and `browser_session_id` when provided via `agent.session()`. |

## Session Enrichment Properties

Properties on `[Agent] Session Enrichment` and `[Agent] Session End` events for session-level analytics.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Quality Score` | float | Overall quality score for the session. |
| `[Agent] Sentiment Score` | float | Sentiment score for the session. |
| `[Agent] Task Failure Type` | string | Type of task failure (e.g., `"hallucination"`, `"refusal"`). |
| `[Agent] Task Failure Reason` | string | Human-readable reason for the task failure. |
| `[Agent] Agent Chain` | string[] | Ordered list of agent IDs involved in the session. |
| `[Agent] Root Agent Name` | string | Name of the root/orchestrating agent. |
| `[Agent] Request Complexity` | string | Complexity classification of the user's request (e.g., `"simple"`, `"complex"`). |

## Reasoning Properties

Reasoning models (OpenAI o1/o3, Anthropic Claude with extended thinking, Google Gemini with thinking) produce internal reasoning content alongside their final response. This is tracked as properties on the `[Agent] AI Response` event -- not as a separate event.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Has Reasoning` | boolean | Whether the response included reasoning/thinking content. Always present when detected (useful for filtering even in `metadata_only` mode). |
| `[Agent] Reasoning Tokens` | int | Number of reasoning/thinking tokens consumed. Always included regardless of privacy tier -- it's an operational metric, not content. |
| `[Agent] Reasoning Content` | string | Raw reasoning text. Only sent when `content_mode="full"`. Truncated at 10K characters. |

Privacy behavior by mode:

| `content_mode` | `Has Reasoning` | `Reasoning Tokens` | `Reasoning Content` |
|-----------------|-----------------|---------------------|---------------------|
| `full` | Yes | Yes | Raw text (max 10K chars) |
| `metadata_only` | Yes | Yes | -- |
| `customer_enriched` | Yes | Yes | -- |

## Model Configuration Properties

The SDK captures *how the model was configured* for each LLM call, enabling prompt A/B testing, model tuning analysis, and configuration drift detection. All properties are set on the `[Agent] AI Response` event.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] System Prompt` | string | The system/developer message content. Only sent when `content_mode="full"` (PII-redacted, truncated at 10K chars). |
| `[Agent] System Prompt Length` | int | Character count of the original system prompt. **Always tracked** regardless of privacy tier -- useful for prompt size trend analysis without content. |
| `[Agent] Temperature` | float | Sampling temperature used for the LLM call. |
| `[Agent] Max Output Tokens` | int | Maximum output token limit configured for the call. |
| `[Agent] Top P` | float | Top-p (nucleus) sampling parameter. |
| `[Agent] Is Streaming` | boolean | Whether the response was streamed. |
| `[Agent] Prompt ID` | string | User-supplied prompt version/template identifier for prompt A/B testing (e.g., `"support-v3.2"`). |

**Auto-capture:** Provider wrappers automatically extract system prompt and model parameters from each provider's native API format. For manual tracking, pass them as keyword arguments to `track_ai_message()`.

**Provider extraction details:**

| Provider | System Prompt Source | Model Params Source |
|----------|---------------------|---------------------|
| OpenAI (Chat) | `messages[0]` where `role in ('system', 'developer')` | `kwargs['temperature']`, `kwargs['max_tokens']`, etc. |
| OpenAI (Responses) | `kwargs['instructions']` | Same as Chat |
| Anthropic | `kwargs['system']` (str or content blocks) | `kwargs['temperature']`, `kwargs['max_tokens']`, etc. |
| Google Gemini | `kwargs['system_instruction']` or model config | `generation_config.temperature`, `generation_config.max_output_tokens`, etc. |
| AWS Bedrock | `kwargs['system']` (Converse API content blocks) | `inferenceConfig.temperature`, `inferenceConfig.maxTokens`, etc. |
| Mistral | `messages[0]` where `role == 'system'` | `kwargs['temperature']`, `kwargs['max_tokens']`, etc. |

## How Behavioral Signals Become Analytics

The SDK captures **behavioral facts** -- not model inference -- on every turn. These facts become queryable properties in Amplitude, and when `content_mode="full"`, they feed server-side enrichments that detect patterns across the full session. The result: SDK signals and server-generated signals converge into the same queryable event stream.

| SDK call | What appears in Amplitude | What you can build |
|---|---|---|
| `track_user_message(is_regeneration=True)` | `[Agent] User Message` with `is_regeneration=True` (immediate) + `[Agent] Session Evaluation` with `behavioral_patterns=["retry_storm"]` (after session ends, when `content_mode="full"`) | Cohort of frustrated users -> target with Guide -> measure churn delta |
| `track_ai_message(was_copied=True)` | `[Agent] AI Response` with `was_copied=True` | Copy rate as positive quality signal -- no explicit rating required |
| `score(source="user", value=1.0)` | `[Agent] Score` with `source="user"` (same event type as server rubric scores with `source="ai"`) | Single chart shows user feedback, LLM-as-judge results, and human annotations side by side -- filtered by `source` |

The first row shows the full chain: the SDK records the behavioral fact immediately, and the server detects the pattern after the session closes. Both events are independently queryable. The third row shows how your `score()` calls and server-generated rubric scores share the same `[Agent] Score` event type -- one chart, all quality signals.

The SDK captures per-turn operational metrics, model configuration, agent hierarchy, and behavioral signals at the application layer. Server-side enrichment classifies the full session after it closes. Both converge into the same charts, cohorts, and funnels you already use for product analytics -- no exports, no joins, no separate tools.

## Implicit Feedback Properties

Behavioral signals that indicate whether an AI response met the user's need -- without requiring explicit ratings. These are properties on existing events, not new event types.

**On `[Agent] User Message`:**

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Is Regeneration` | boolean | User clicked "regenerate" to get a new response for the same input. Only set when `true`. |
| `[Agent] Is Edit` | boolean | User edited a previous message and resubmitted. Only set when `true`. |
| `[Agent] Edited Message ID` | string | The `message_id` of the original message that was edited, linking the edit to the original. |

**On `[Agent] AI Response`:**

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Was Copied` | boolean | User copied the AI response content (e.g., clipboard copy). Only set when `true`. |

**On `[Agent] Session End`:**

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Abandonment Turn` | int | Turn number at which the user abandoned the session. A value of 1 strongly signals the first response did not satisfy. |

**What this enables:**
- Regeneration rate per model/prompt/agent -- a direct proxy for response quality
- Edit patterns to detect ambiguous or hard-to-express user intents
- Copy rate as a positive signal (the user found the response useful enough to use elsewhere)
- Abandonment analysis to identify sessions where users gave up, segmented by turn depth

## Attachment Properties

Rich media references for files, images, audio, and video attached to user or AI messages. **File content is never transmitted to Amplitude.** Include a `url` to your resource and the LLM session viewer renders it on-the-fly from the reviewer's browser, using your existing infrastructure and access controls.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Has Attachments` | boolean | Whether this message includes file attachments. |
| `[Agent] Attachment Count` | int | Number of attached files. |
| `[Agent] Attachment Types` | string[] | Deduplicated list of file types (e.g., `["pdf", "image"]`). |
| `[Agent] Total Attachment Size Bytes` | int | Sum of `size_bytes` across all attachments. Only set when at least one attachment provides `size_bytes`. |
| `[Agent] Attachments` | string (JSON) | Serialized array of attachment dicts. |

The SDK recognizes four keys for rendering and analytics. All other keys are preserved as-is in the serialized JSON:

| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `type` | string | Recommended | Content type: `"image"`, `"pdf"`, `"csv"`, `"audio"`, `"video"`, `"code"`, etc. Determines how the session viewer renders the attachment. Defaults to `"unknown"`. |
| `name` | string | Recommended | Display name or filename. |
| `url` | string | No | URL to the resource on your infrastructure. When provided, the LLM session viewer fetches and renders the content directly in the reviewer's browser -- no Amplitude storage or proxying involved. Works with CDNs, S3, internal doc systems, or any URL reachable from the reviewer's network. |
| `mime_type` | string | No | MIME type (e.g., `"image/png"`, `"application/pdf"`). Helps the viewer choose the right rendering strategy. |

Add any additional keys you need -- `size_bytes`, `page_count`, `duration_seconds`, `department`, `internal_doc_id`, etc. They are serialized into `[Agent] Attachments` and available to viewers and your own tooling.

## Cache Token Properties

LLM providers support prompt caching, where repeated token prefixes (system prompts, tool definitions, conversation history) are cached and billed at a reduced rate. The SDK tracks cache token breakdowns on the `[Agent] AI Response` event to enable accurate cost calculation.

| Property | Type | Description |
|----------|------|-------------|
| `[Agent] Cache Read Tokens` | int | Number of input tokens served from the provider's prompt cache. Billed at a reduced rate (~10% for Anthropic, ~50% for OpenAI). |
| `[Agent] Cache Creation Tokens` | int | Number of input tokens written to the provider's prompt cache. Billed at a premium rate (~125% for Anthropic). |

**Cost calculation behavior:** When `cache_read_tokens` or `cache_creation_tokens` are provided but `total_cost_usd` is omitted, the SDK auto-calculates cost using cache-aware pricing via [genai-prices](https://pypi.org/project/genai-prices/). Cache read tokens are priced at the provider's discounted rate, and cache creation tokens at the premium rate. This produces significantly more accurate cost estimates for multi-turn sessions where the majority of input tokens are cache hits. If `total_cost_usd` is explicitly provided, it is used as-is.

All content properties respect the configured `content_mode`. See the [Privacy & Content Control](../../README.md#privacy--content-control) section for tier details.
