Imported from aaron-peloquin/ax-analytics (
.agents/skills/ax-analytics-telemetry/SKILL.md). Install upstream withnpx skills add aaron-peloquin/ax-analytics --skill ax-analytics-telemetry. Copyright stays with the author.
AX Analytics Telemetry Integration Skill
System Overview
AX Analytics is a high-throughput, language-agnostic AI agent and web telemetry platform. It provides real-time visualization of multi-turn AI agent trajectory flows (Sankey diagrams), side-by-side tool performance hubs (Sunburst charts), sticky A/B experiment resolution, and OpenTelemetry / Opik trace correlation.
Key Operational Capabilities
- 3-Tier Identity Trajectory Flows: Connects user sessions (
sessionId), orchestrators (multiagentIdentity), and worker agents (agentIdentity/entityId) into Directed Acyclic Graph (DAG) Sankey trajectory flows (previousToolName->invokedToolName). - Outcome Metrics: Measures Seconds to Resolution (
executionTimeMs / 1000) and Cost Per Outcome ($ expenditure per successful run). - OTEL GenAI Attribute Tracking: Records LLM vendor (
provider), model (model), prompt tokens (inputTokens), and completion tokens (outputTokens). - Sticky A/B Experimentation: Deterministic 0-100% variant hashing based on
hash(entity_id + experiment_id) % 100. - Parameter Share Analysis: Evaluates parameter values with an automatic ≥ 8% share threshold grouping rule.
- OpenTelemetry Correlation: Direct trace/span mapping via W3C
traceparentheaders (otelTraceId,otelSpanId).
3-Tier Identity Taxonomy & Metadata Groupings
To ensure accurate aggregation across analytics dashboards, trajectory flows, and cost models, telemetry callers MUST categorize metadata across three distinct hierarchical scopes:
| Scope Level | Field Name | Architectural Purpose & Definition | Concrete Example |
|---|---|---|---|
| 1. User Journey Scope | sessionId |
Binds the user request journey across multi-turn interactions over time. Auto-generated by server if omitted. | "sess_usr_98124_chat" or W3C Trace GUID |
| 2. Multi-Agent System Scope | multiagentIdentity |
System-wide multi-agent grouping identifier. Stamped on EVERY event emitted by ALL participating agents across the entire execution chain (entrypoint, primary worker, intermediate helper, or tertiary sub-agent). | "customer-triage-system", "code-review-pipeline", "campaign-generation-workflow" |
| 3. Individual Agent Scope | entityId (or agentIdentity) |
Identifies the specific AI agent persona, worker loop, or MCP tool worker executing that particular turn/step. | "retrieval-agent", "sql-generator", "summarization-worker" |
[!IMPORTANT] Implementation Guidance for
multiagentIdentity:multiagentIdentityis NOT restricted to root spans or primary orchestrators. It is an overarching context string stamped on every single event emitted by every participating agent throughout the entire execution chain. It binds all constituent agent steps (entityId) into a unified multi-agent system view for whole-chain cost tracking, full-pipeline latency aggregation, and cross-agent trajectory flow mapping.
Prescriptive Agent Entity Naming Standard (entityId)
To ensure accurate aggregation across Sankey flow diagrams and Sunburst hubs, callers MUST adhere to prescriptive entity naming conventions for entityId:
- Agent Personas: Use clean, descriptive hyphenated or colon-scoped names representing the specific AI persona or worker role (e.g.
retrieval-agent,sql-generator,sales-assistant). - System & Route Endpoints: When telemetry originates from internal service routes or MCP servers, set
entityIdto the endpoint path (e.g./api/v1/chat,/api/mcp). - Stage-Aware Execution Contexts: Append execution stages for fine-grained trajectory tracking when an agent transitions through phases (e.g.
"rag-agent: warming"during index load vs"rag-agent"during live synthesis). - Deterministic Fallback Cascade: When
entityIdis omitted, telemetry integrations MUST evaluate fallbacks in order of specificity:entityId->agentIdentity-> service route path ->"agent-service".
Telemetry Semantics & OpenTelemetry Boundary Guidelines
To ensure clean Sankey trajectory flows and accurate Sunburst performance hubs, callers MUST adhere to the following telemetry boundaries:
1. Agent Tool Calls vs. Internal Code Execution (Temporal Activities, DB, STT/TTS)
- Strictly Agentic:
eventType: "tool_call"(andinvokedToolName) is strictly reserved for Agentic Tool Invocations—specifically when an AI agent reasons and autonomously decides to call an external tool (e.g., an MCP server tool likeget_campaign_planorsearch_lore). - No Synthetic Tool Calls for Background Code: Standard code-level tasks or background workflow activities (e.g., Temporal activities, PostgreSQL queries, speech-to-text transcriptions, text-to-speech audio synthesis, or vector indexing) MUST NOT emit synthetic
tool_callor customtemporal_activityevents to AX Analytics. Doing so pollutes the Sankey trajectory flow diagrams and Sunburst hubs.
2. Entity Type (entityType) Semantics
entityType: "agent": MUST only be attached when an AI persona or agent entity explicitly takes an autonomous action (e.g.dm-persona,bookkeeper-agent).entityType: "human": Used for real human user interactions (e.g. UI clicks, form submissions, frontend page views).- Deterministic System Workers: If deterministic backend code or a background system worker is running a routine function,
entityTypeMUST be left undefined / null (omitted) rather than defaulting to"agent".
3. Telemetry Destination Decision Matrix
| Execution Task / Scenario | Target Telemetry System | eventType |
entityType |
invokedToolName |
Architectural Rationale |
|---|---|---|---|---|---|
AI Agent calls MCP Tool (e.g. get_campaign_plan) |
AX Analytics | "tool_call" |
"agent" |
"get_campaign_plan" |
Autonomous reasoning step; feeds Sankey trajectory flows & Sunburst hubs. |
| Temporal Workflow Activity (e.g. STT/TTS synthesis) | OpenTelemetry Span | N/A (OTel span) | N/A | N/A | Deterministic workflow task; synthetic tool calls pollute agent decision flows. |
| PostgreSQL / Vector DB Query | OpenTelemetry DB Span | N/A (OTel span) | N/A | N/A | Database latency and execution traces correlate via otelTraceId. |
| GenAI LLM Prompt / Completion Turn | AX Analytics | "llm_inference" |
"agent" |
omitted / null | Tracks token costs, model performance, and seconds to resolution. |
| Human User UI Click or Form Submit | AX Analytics | "button_click" |
"human" |
omitted / null | Captures user frontend journey and conversion metrics. |
| Deterministic Backend Worker / Cron Job | OpenTelemetry Span | custom or N/A | undefined / omitted | N/A | Non-autonomous code; leave entityType empty if emitting custom AX metric. |
Automated Session Trajectory Flow Tracking
To eliminate manual caller overhead when recording sequential tool invocations, telemetry integrations SHOULD maintain an in-memory session registry (sessionLastToolMap):
- Automatic Preceding Tool Lookup: When an event with
eventType: "tool_call"is logged without an explicitpreviousToolName, retrieve the preceding tool fromsessionLastToolMap.get(sessionId). - Bootstrap Initialization: If no preceding tool exists for
sessionId, defaultpreviousToolNameto"init_session". - Registry Update: Immediately update the session registry with
sessionLastToolMap.set(sessionId, invokedToolName).
Dynamic Endpoint & Environment Configuration
Telemetry integrations SHOULD dynamically resolve host and app key configurations based on runtime environment context:
- Browser Environments: Proxy ingestion requests through
/api/ax-analytics(via Next.js rewrite or equivalent web server proxy) to avoid CORS issues and expose a unified endpoint. - Server Environments: Read environment variables
AX_ANALYTICS_HOSTorNEXT_PUBLIC_AX_ANALYTICS_HOST, falling back tohttp://localhost:4400. - App Key Resolution: Read
AX_ANALYTICS_APP_KEYorNEXT_PUBLIC_AX_ANALYTICS_APP_KEY, specifying the target application/tenant scope (e.g.customer_support_prod,doc_assistant_dev).
Ingestion Payload Field Contract (_v1)
| Field Name | Type | Required | Category | Description & System Usage |
|---|---|---|---|---|
appKey |
string | Yes | System | Application key identifier (e.g. customer_support_prod). Used for multi-tenant and environment isolation. |
sessionId |
string | No | Identity | User session GUID or trace ID root. Connects multi-turn agent execution steps into Sankey flows. Auto-generated by server if omitted. |
multiagentIdentity |
string | No | Identity | System-wide multi-agent grouping identifier stamped across ALL agents in the execution chain (e.g. customer-triage-system, code-review-pipeline). |
entityId (or agentIdentity) |
string | Yes | Identity | Persistent identifier for human user (user_4821), agent persona (sales-assistant), worker loop (sql-generator), or stage (rag-agent: warming). Used in sticky A/B hashing hash(entity_id + exp_id) % 100. |
entityType |
'human' | 'agent' |
No | Dimension | Type of entity originating the event ('agent' for autonomous AI personas, 'human' for user actions). Leave undefined / omitted for deterministic system workers. |
eventType |
string | No | Dimension | Event type identifier ('tool_call', 'llm_inference', 'page_view', 'button_click'). |
invokedToolName |
string | No | Dimension | Tool invoked by the agent (execute_sql_query). Strictly for autonomous agent tool calls (e.g. MCP tools). Forms inner hub for Sunburst & target node in Sankey. |
previousToolName |
string | No | Dimension | Preceding tool invoked (parse_user_prompt). Forms source node in Sankey trajectory flow diagrams. Automatically populated if omitted. |
provider |
string | No | OTEL GenAI | LLM Vendor / System provider (gen_ai.system, e.g., 'openai', 'anthropic', 'google', 'ollama'). |
model |
string | No | OTEL GenAI | LLM Model string (gen_ai.request.model, e.g., 'gpt-4o', 'claude-3-5-sonnet'). |
inputTokens |
number | No | OTEL GenAI | Prompt / Input token count (gen_ai.usage.input_tokens). |
outputTokens |
number | No | OTEL GenAI | Completion / Output token count (gen_ai.usage.output_tokens). |
params |
object | No | Dimension | Tool JSON parameters. Evaluated in Sunburst outer ring with the ≥ 8% share threshold rule. |
results |
object | No | Payload | Output JSON result object or LLM output content. |
statusCode |
Enum | No | Dimension | Outcome status (SUCCESS, PARAMETER_ERROR, TIMEOUT, AUTH_DENIED, MODEL_REFUSAL, ASSERTION_FAILED). Feeds Successful vs Failed Sunburst hubs. |
executionTimeMs |
number | No | Metric | Turn duration in milliseconds. Converted to Seconds to Resolution (executionTimeMs / 1000) on outcome cards. |
tokenCost |
number | No | Metric | Turn LLM token expenditure in USD ($). Used to calculate Cost Per Outcome (Total Cost / Successful Runs). |
otelTraceId |
string | No | Dimension | OpenTelemetry 128-bit hex trace ID extracted from W3C traceparent. Links telemetry rows directly to Opik trace logs. |
otelSpanId |
string | No | Dimension | OpenTelemetry 64-bit hex span ID. |
assignedVariant |
string | No | Dimension | Sticky A/B experiment variant assigned for the session ('A', 'B', defaulting to 'Standard'). |
Sequential Integration Workflow
- Initialize Session Context: Extract W3C
traceparent(00-<traceId>-<spanId>-01) or provide a uniquesessionId(or let server auto-generateax_sess_*). - Resolve Experiment Variant (Optional): Query
POST /v1/experiments/variantwithexperimentKeyand prescriptiveentityId. - Execute Tool / LLM Inference: Record turn start time and execute the requested agent tool or inference.
- Emit Telemetry Event: Call
POST /v1/telemetry/event(or helper functiontrackAgentToolCall) with execution time, token cost, input/output tokens, provider, model, parameters, results, and trace IDs. - Submit User Feedback: Send thumbs up/down votes and comments via
POST /v1/feedbackat session completion.
API Endpoints & cURL Specifications
[!TIP] Before making new network requests, search for an reuse any existing helpers that previous engineers may have already setup for your project.
1. Ingest Telemetry Event / Tool Call (POST /v1/telemetry/event)
curl -X POST http://localhost:4400/v1/telemetry/event \
-H "Content-Type: application/json" \
-d '{
"appKey": "customer_support_prod",
"sessionId": "sess_usr_98124_chat",
"multiagentIdentity": "customer-triage-system",
"entityId": "retrieval-agent",
"entityType": "agent",
"eventType": "tool_call",
"invokedToolName": "search_knowledge_base",
"previousToolName": "init_session",
"provider": "openai",
"model": "gpt-4o",
"inputTokens": 850,
"outputTokens": 120,
"params": { "query": "order refund status", "topK": 3 },
"results": { "status": "active", "docsFound": 3 },
"statusCode": "SUCCESS",
"executionTimeMs": 240,
"tokenCost": 0.0018,
"otelTraceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"otelSpanId": "00f067aa0ba902b7"
}'
2. Ingest Non-Tool LLM Inference (POST /v1/telemetry/event)
curl -X POST http://localhost:4400/v1/telemetry/event \
-H "Content-Type: application/json" \
-d '{
"appKey": "customer_support_prod",
"sessionId": "sess_usr_98124_chat",
"multiagentIdentity": "customer-triage-system",
"entityId": "summarization-worker",
"entityType": "agent",
"eventType": "llm_inference",
"provider": "anthropic",
"model": "claude-3-5-sonnet",
"inputTokens": 1200,
"outputTokens": 350,
"params": {
"prompt": "Summarize customer refund conversation.",
"temperature": 0.3
},
"results": {
"response": "Customer requested a refund due to delayed shipment. Resolution issued under policy #402."
},
"statusCode": "SUCCESS",
"executionTimeMs": 450,
"tokenCost": 0.0032,
"otelTraceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"otelSpanId": "00f067aa0ba902b7"
}'
3. Ingest Human Web Pageview OTLP Trace (POST /v1/telemetry/otlp/v1/traces)
[!NOTE]
user.type: "human"denotes real human visitors navigating the web frontend. Human users generatedocumentLoadpageview events (URL path, title, referrer, visibility state, device desktop/mobile). This is distinct from AI agents (user.type: "agent"), which execute backend tools/prompts.
curl -X POST http://localhost:4400/v1/telemetry/otlp/v1/traces \
-H "Content-Type: application/json" \
-d '{
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"parentSpanId": "5e1074e531853683",
"name": "documentLoad",
"startTime": [1700000000, 100000000],
"endTime": [1700000000, 850000000],
"attributes": {
"url.full": "https://example.com/products/headphones",
"url.scheme": "https",
"url.path": "/products/headphones",
"user_agent.original": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/122.0.0.0 Safari/537.36",
"document.title": "Wireless Headphones - Shop",
"document.referrer": "https://google.com",
"document.visibilityState": "visible",
"app.key": "app_live_8832109",
"app.event_type": "page_view",
"session.id": "web_sess_99201",
"user.id": "user_4821",
"user.type": "human"
},
"resource": {
"attributes": {
"service.name": "web-frontend",
"browser.platform": "macOS",
"browser.mobile": false,
"browser.brands": ["Google Chrome 122", "Chromium 122"]
}
}
}'
3. Resolve Sticky A/B Experiment (POST /v1/experiments/variant)
curl -X POST http://localhost:4400/v1/experiments/variant \
-H "Content-Type: application/json" \
-d '{
"appKey": "customer_support_prod",
"experimentKey": "proactive_rag_retrieval_v2",
"entityId": "retrieval-agent"
}'
4. Reset Sticky User/Agent Assignments (POST /v1/experiments/reset-assignments)
curl -X POST http://localhost:4400/v1/experiments/reset-assignments \
-H "Content-Type: application/json" \
-d '{
"experimentKey": "proactive_rag_retrieval_v2"
}'
5. Submit Session Feedback (POST /v1/feedback)
curl -X POST http://localhost:4400/v1/feedback \
-H "Content-Type: application/json" \
-d '{
"appKey": "customer_support_prod",
"sessionId": "sess_usr_98124_chat",
"entityId": "retrieval-agent",
"vote": 1,
"comment": "Resolved user query accurately with RAG context."
}'