Skip to main content

Official Python SDK for Surfa Analytics - Ingest live traffic events

Project description

Surfa Ingest SDK

PyPI version Python Support License: MIT Downloads

Official Python SDK for ingesting live traffic events to Surfa Analytics.

Features

  • 🚀 Event Buffering - Automatic batching with configurable buffer size
  • 🔄 Auto-Retry - Built-in retry logic with exponential backoff
  • 📦 Context Manager - Automatic session lifecycle management
  • 🏷️ Runtime Metadata - Track AI provider, model, and configuration
  • Event Validation - Client-side validation before sending
  • 🔍 Correlation IDs - Link related events together
  • 📊 Session Tracking - Automatic session ID generation
  • 🛡️ Type Safety - Full type hints and IDE autocomplete

Deterministic Metrics

When you send events using this SDK, the Surfa platform automatically calculates these metrics for each execution:

Automatically Calculated Metrics

Metric Definition How It's Calculated
Task Completion Whether the task was actually completed Uses task_completed field if present, otherwise infers from event sequence
Total Steps Number of agent steps taken Count of tool call events
Tool Calls Total number of tool invocations Count of tool_call_started events
Retries Repeated calls with same tool+args Detected from tool_name + payload.input matching
Reattempts Retries after a failed call Retries where previous attempt had status: "error"
Redundant Calls Retries after a successful call Retries where previous attempt had status: "success"
Schema Errors Schema validation failures Count of schema_validation_error events
Hallucinated Calls Calls to non-existent tools Detected from error patterns
Recovery Agent recovered from errors First success after any failure
Total Latency Sum of all operation latencies Sum of latency_ms fields
P95 Latency 95th percentile latency Calculated from latency_ms distribution

What You Need to Send

For accurate metrics, ensure your events include:

Required Fields:

  • kind - Event type ("tool", "session", "runtime")
  • subtype - Event subtype ("call_started", "call_completed", etc.)

Recommended Fields:

  • tool_name - For retry detection
  • payload.input - Tool arguments (for retry detection)
  • correlation_id - To pair request/response events
  • latency_ms - For latency metrics
  • status - "success" or "error" for completion tracking

Example:

# This event contributes to multiple metrics automatically
client.track({
    "kind": "tool",
    "subtype": "call_completed",
    "tool_name": "search_web",
    "payload": {
        "input": {"query": "AI news"}  # Used for retry detection
    },
    "correlation_id": "abc123",
    "latency_ms": 234,
    "status": "success"
})

No Client-Side Calculation Needed

Don't do this:

# You don't need to track retries yourself!
is_retry = check_if_retry(params)  # Not needed
client.track({"is_retry": is_retry})  # Server calculates this

Do this instead:

# Just send clean events - server handles the rest
client.track({
    "kind": "tool",
    "subtype": "call_started",
    "tool_name": "search_web",
    "payload": {"input": {"query": "AI news"}}
})

The platform automatically detects retries, calculates latencies, and tracks all metrics from your event stream.

Installation

pip install surfa-ingest

Quick Start

from surfa_ingest import SurfaClient

# Initialize client with your ingest key
client = SurfaClient(ingest_key="sk_live_your_key_here")

# Track events
client.track({
    "kind": "tool",
    "subtype": "call_started",
    "tool_name": "search_web",
    "args": {"query": "AI news"}
})

client.track({
    "kind": "tool",
    "subtype": "call_completed",
    "tool_name": "search_web",
    "status": "success",
    "latency_ms": 234
})

# Flush events to API
client.flush()

Context Manager (Recommended)

Use the context manager to automatically track session lifecycle:

from surfa_ingest import SurfaClient

with SurfaClient(ingest_key="sk_live_your_key_here") as client:
    # Session automatically started
    
    client.track({
        "kind": "tool",
        "subtype": "call_started",
        "tool_name": "search_web"
    })
    
    # Session automatically ended and events flushed on exit
    # task_completed automatically set based on success/failure

Explicit Task Completion

Mark whether a task was actually completed:

# Explicit success
with SurfaClient(ingest_key="sk_live_...") as client:
    result = perform_task()
    client.session_end(task_completed=True)

# Explicit failure
with SurfaClient(ingest_key="sk_live_...") as client:
    try:
        result = perform_task()
        client.session_end(task_completed=True)
    except Exception:
        client.session_end(task_completed=False)
        raise

# Automatic (context manager infers from exceptions)
with SurfaClient(ingest_key="sk_live_...") as client:
    result = perform_task()  # If exception: task_completed=False
    # If no exception: task_completed=True

Configuration

client = SurfaClient(
    ingest_key="sk_live_your_key_here",
    api_url="https://api.surfa.dev",  # Default: http://localhost:3000
    flush_at=25,                       # Auto-flush after 25 events
    timeout_s=10,                      # HTTP timeout in seconds
)

Set Runtime Metadata

Track which AI runtime is being used:

client = SurfaClient(ingest_key="sk_live_...")

client.set_runtime(
    provider="anthropic",
    model="claude-sonnet-4-5",
    mode="messages"
)

Event Types

Tool Events

# Tool call started
client.track({
    "kind": "tool",
    "subtype": "call_started",
    "tool_name": "search_web",
    "direction": "request",
    "args": {"query": "Python tutorials"}
})

# Tool call completed
client.track({
    "kind": "tool",
    "subtype": "call_completed",
    "tool_name": "search_web",
    "direction": "response",
    "status": "success",
    "latency_ms": 234,
    "results": [{"title": "Learn Python", "url": "..."}]
})

Session Events

# Session started
client.session_started()

# Session ended
client.session_ended()

Runtime Events

# LLM request
client.track({
    "kind": "runtime",
    "subtype": "llm_request",
    "direction": "outbound",
    "messages": [{"role": "user", "content": "Hello"}],
    "temperature": 0.7
})

Event Fields

Required Fields

  • kind (str): Event type (e.g., "tool", "session", "runtime")

Optional Fields

  • subtype (str): Event subtype (e.g., "call_started", "session_ended")
  • tool_name (str): Name of the tool
  • status (str): Status (e.g., "success", "error")
  • direction (str): Direction (e.g., "request", "response")
  • method (str): HTTP method or similar
  • correlation_id (str): Correlation ID for pairing events
  • span_parent_id (str): Parent span ID for tracing
  • latency_ms (int): Latency in milliseconds
  • ts (str): Timestamp (ISO 8601 format, auto-generated if not provided)
  • Any additional fields will be included in the event payload

Auto-Flush

Events are automatically flushed when:

  1. Buffer reaches flush_at events (default: 25)
  2. Context manager exits
  3. flush() is called explicitly

Error Handling

from surfa_ingest import SurfaClient, SurfaConfigError, SurfaValidationError

try:
    client = SurfaClient(ingest_key="invalid_key")
except SurfaConfigError as e:
    print(f"Configuration error: {e}")

try:
    client.track({"invalid": "event"})  # Missing 'kind'
except SurfaValidationError as e:
    print(f"Validation error: {e}")

Logging

The SDK uses Python's standard logging module:

import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("surfa_ingest")

Development Status

Current Version: 0.1.0 (Alpha)

This SDK is in active development. The API may change in future versions.

Implemented

  • ✅ Client initialization
  • ✅ Event buffering
  • ✅ Session management
  • ✅ Context manager support
  • ✅ Event validation
  • ✅ Runtime metadata
  • ✅ HTTP API integration
  • ✅ Automatic retry logic (3 retries with exponential backoff)

Coming Soon

  • 🔜 Background flushing
  • 🔜 Async support

License

MIT

Links

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

0.1.0 (2026-02-20)

  • Initial release
  • Event buffering and batching
  • Session management
  • Context manager support
  • Runtime metadata capture
  • HTTP API integration with retry logic
  • Event validation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

surfa_ingest-0.1.1.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

surfa_ingest-0.1.1-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file surfa_ingest-0.1.1.tar.gz.

File metadata

  • Download URL: surfa_ingest-0.1.1.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for surfa_ingest-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d11d3fe73c7185ac4c42b6a0607052edb27bab68de78110a325667b509d170f7
MD5 b07a1b91b42822757a334c8453412a0c
BLAKE2b-256 6f1d1e82cce8172310cd9a7a4007ba9ce70f7677bc7cf21eeaa58d2c110391a4

See more details on using hashes here.

File details

Details for the file surfa_ingest-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: surfa_ingest-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for surfa_ingest-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 da4939626c657d2d2578cf239a7848d44737350eaf6a687482cc1e5cec7d6a06
MD5 309242537bc7a7de7d3edf27ea10eb59
BLAKE2b-256 16e86e8ffd36e0aa4c3da9eec6b45b055571fd580a53dbf1341d4d7931a91ac3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page