Skip to main content

Python SDK for March AI Conversation History API

Project description

March Conversation History SDK

A Python SDK for the March AI Conversation History API with full type safety, automatic retries, and pagination support.

Features

Type-Safe: Full type hints with Pydantic v2 models 🔄 Auto-Retry: Exponential backoff with configurable retry logic 📄 Auto-Pagination: Iterate over large result sets effortlessly 🚀 Sync & Async: Support for both synchronous and asynchronous operations 🧹 Auto-Cleanup: No context managers needed - automatic resource management 🎯 Best Practices: Follows Python SDK design patterns used by major APIs

Installation

pip install march-history

Or install from source:

git clone https://github.com/march/march-history-sdk
cd march-history-sdk
pip install -e .

Quick Start

from march_history import MarchHistoryClient
from march_history.models import MessageRole, ConversationStatus

# Create client - no context manager needed!
client = MarchHistoryClient(base_url="http://localhost:8000")

# Create a conversation
conv = client.conversations.create(
    tenant_name="acme-corp",
    user_id="user-123",
    title="Customer Support Session",
    metadata={"session_id": "sess-456"}
)

# Add messages
msg1 = client.messages.create(
    conversation_id=conv.id,
    role=MessageRole.USER,
    content="Hello, I need help with my order"
)

msg2 = client.messages.create(
    conversation_id=conv.id,
    role=MessageRole.ASSISTANT,
    content="I'd be happy to help! What's your order number?"
)

# List all messages in conversation
messages = client.messages.list(conversation_id=conv.id)
for msg in messages:
    print(f"{msg.role}: {msg.content}")

# Auto-pagination - iterate over all conversations
for conversation in client.conversations.list_iter(tenant_name="acme-corp"):
    print(f"Conversation: {conversation.title}")

# Search conversations
results = client.conversations.search(
    q="support",
    status=ConversationStatus.ACTIVE
)

# Archive conversation when done
client.conversations.archive(conv.id)

# No need to call client.close() - automatic cleanup!

Usage Guide

Creating Conversations

# Basic conversation
conv = client.conversations.create(
    tenant_name="acme-corp",
    user_id="user-123",
    title="Support Chat"
)

# With full metadata
conv = client.conversations.create(
    tenant_name="acme-corp",
    user_id="user-123",
    title="Sales Inquiry",
    agent_identifier="sales-bot-v2",
    status=ConversationStatus.ACTIVE,
    metadata={
        "session_id": "sess-456",
        "source": "web_chat",
        "priority": "high"
    }
)

Working with Messages

# Single message
msg = client.messages.create(
    conversation_id=conv.id,
    role=MessageRole.USER,
    content="What are your business hours?",
    metadata={"client_ip": "192.168.1.1"}
)

# Batch create messages
msgs = client.messages.create_batch(
    conversation_id=conv.id,
    messages=[
        {"role": "user", "content": "Hello"},
        {"role": "assistant", "content": "Hi! How can I help?"},
        {"role": "user", "content": "I need information"},
    ]
)

# Search messages in a conversation
results = client.messages.search(
    conversation_id=conv.id,
    q="business hours"
)

# Search across all conversations
all_results = client.messages.search_global(
    q="error",
    role=MessageRole.ASSISTANT
)

Pagination

# Manual pagination - single page
conversations = client.conversations.list(
    tenant_name="acme-corp",
    offset=0,
    limit=50
)

# Auto-pagination - iterate over all items
for conv in client.conversations.list_iter(
    tenant_name="acme-corp",
    page_size=100  # Items per page
):
    print(conv.title)

# Limit total items fetched
for conv in client.conversations.list_iter(
    tenant_name="acme-corp",
    max_items=500  # Stop after 500 items
):
    print(conv.title)

Searching

# Search conversations by title
results = client.conversations.search(q="customer support")

# Search by metadata
results = client.conversations.search(
    metadata_key="environment",
    metadata_value="production"
)

# Combined search with filters
results = client.conversations.search(
    q="order",
    status=ConversationStatus.ACTIVE,
    tenant_name="acme-corp",
    agent_identifier="support-bot-v1"
)

# Search with auto-pagination
for conv in client.conversations.search_iter(q="urgent"):
    print(conv.title)

Managing Tenants

# List all tenants
tenants = client.tenants.list()

# Get tenant by ID
tenant = client.tenants.get(tenant_id=1)

# Get tenant by name
tenant = client.tenants.get_by_name("acme-corp")

# Iterate over all tenants
for tenant in client.tenants.list_iter():
    print(tenant.name)

Configuration

Basic Configuration

client = MarchHistoryClient(
    base_url="http://localhost:8000",
    timeout=60.0,  # Request timeout in seconds
    max_retries=5,  # Maximum retry attempts
)

Advanced Retry Configuration

from march_history.config import RetryConfig

client = MarchHistoryClient(
    base_url="http://localhost:8000",
    retry_config=RetryConfig(
        max_retries=5,
        backoff_factor=2.0,  # Exponential backoff multiplier
        retry_status_codes=(408, 429, 500, 502, 503, 504),
        max_backoff_seconds=120.0  # Max backoff time
    )
)

API Key Authentication

# Using api_key parameter (recommended)
client = MarchHistoryClient(
    base_url="http://localhost:8000",
    api_key="your-api-key-123"  # Sent as X-API-Key header
)

Custom Headers

client = MarchHistoryClient(
    base_url="http://localhost:8000",
    api_key="your-api-key",  # API key authentication
    custom_headers={
        "X-Custom-Header": "value"  # Additional custom headers
    }
)

Error Handling

The SDK provides a comprehensive exception hierarchy:

from march_history.exceptions import (
    MarchHistoryError,  # Base exception
    APIError,  # Base for API errors
    ValidationError,  # 422 validation errors
    NotFoundError,  # 404 not found
    ConflictError,  # 409 conflict (e.g., duplicate sequence number)
    BadRequestError,  # 400 bad request
    ServerError,  # 500+ server errors
    NetworkError,  # Network/connection errors
    RetryError,  # Max retries exceeded
)

try:
    conv = client.conversations.get(999)
except NotFoundError as e:
    print(f"Conversation not found: {e.message}")
    print(f"Status code: {e.status_code}")
    print(f"Error details: {e.details}")
except ValidationError as e:
    print(f"Validation failed: {e.message}")
    for detail in e.details:
        print(f"  - {detail['field']}: {detail['message']}")
except RetryError as e:
    print(f"Max retries exceeded: {e}")
    print(f"Last error: {e.last_exception}")
except APIError as e:
    print(f"API error: {e}")

Advanced Usage

Optional Context Manager

While not required, you can use context managers for explicit resource control:

# Guaranteed cleanup even if exceptions occur
with MarchHistoryClient(base_url="http://localhost:8000") as client:
    conv = client.conversations.create(
        tenant_name="acme-corp",
        user_id="user-123",
        title="Chat"
    )
    # ... work with client ...
# Connections automatically closed

Accessing Response Metadata

All models provide access to timestamps and IDs:

conv = client.conversations.create(
    tenant_name="acme-corp",
    user_id="user-123",
    title="Support"
)

print(f"ID: {conv.id}")
print(f"Tenant ID: {conv.tenant_id}")
print(f"User ID: {conv.user_id}")
print(f"Created: {conv.created_at}")
print(f"Updated: {conv.updated_at}")
print(f"Metadata: {conv.metadata}")

Working with Metadata

Metadata fields accept arbitrary JSON:

# Store custom data
conv = client.conversations.create(
    tenant_name="acme-corp",
    user_id="user-123",
    title="Support",
    metadata={
        "user_email": "user@example.com",
        "session": {
            "id": "sess-456",
            "tier": "premium"
        },
        "source": "mobile_app",
        "version": "1.2.3",
        "tags": ["urgent", "billing"]
    }
)

# Update metadata
conv = client.conversations.update(
    conv.id,
    metadata={
        **conv.metadata,
        "resolved": True,
        "resolution_time": 300
    }
)

Type Safety

The SDK is fully typed for excellent IDE support:

from march_history.models import MessageRole, ConversationStatus

# Type-safe enums
role: MessageRole = MessageRole.USER
status: ConversationStatus = ConversationStatus.ACTIVE

# Pydantic models validate at runtime
try:
    client.messages.create(
        conversation_id=1,
        role="invalid_role",  # Will raise ValidationError
        content="Hello"
    )
except ValidationError as e:
    print(f"Invalid role: {e}")

Examples

See the examples/ directory for more examples:

Requirements

  • Python 3.11+
  • httpx >= 0.25.0
  • pydantic >= 2.0.0

Development

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=march_history --cov-report=html

# Run type checking
mypy src/march_history

# Run linting
ruff check src/march_history

# Format code
ruff format src/march_history

Testing

The SDK includes comprehensive tests:

  • Unit tests: Models, exceptions, configuration
  • Integration tests: Resources, API interactions (mocked with respx)
  • Pagination tests: Auto-pagination, page iterators
  • Retry tests: Exponential backoff, retry configuration

Run all tests:

pytest

Run specific test files:

pytest tests/test_models.py
pytest tests/test_resources.py
pytest tests/test_retry.py

Run with verbose output:

pytest -v

Test coverage:

pytest --cov=march_history --cov-report=term-missing

License

MIT License - see LICENSE file for details.

Contributing

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

Support

For issues and questions:

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

march_history-0.2.1.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

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

march_history-0.2.1-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

Details for the file march_history-0.2.1.tar.gz.

File metadata

  • Download URL: march_history-0.2.1.tar.gz
  • Upload date:
  • Size: 34.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for march_history-0.2.1.tar.gz
Algorithm Hash digest
SHA256 5f822bd5a5410092e2a2cc872805092dc48bc9fc670abc5047578dc7b4d0c36e
MD5 269d0c9c341b8735cec588a28d32b977
BLAKE2b-256 3a911a11308eb9f2443dc57c187b9aa5d81d6f829bdc3fc68f0e8c1046e6bf2c

See more details on using hashes here.

File details

Details for the file march_history-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: march_history-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 29.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for march_history-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0f48c7d506e7410989db86670e8f29e4f5dd82f419fbc10007591dfa89edf8cd
MD5 c4df76fff7dcea6ffb00ef070f63724a
BLAKE2b-256 b9fbfaebcaee0bae4af39e11fc8a8c68a8350db46b6023fbed2b4d10f0d8f989

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