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!
Async Usage
The SDK provides a fully async client for use with asyncio:
import asyncio
from march_history import AsyncMarchHistoryClient
from march_history.models import MessageRole, ConversationStatus
async def main():
# Create async client - no context manager needed!
client = AsyncMarchHistoryClient(base_url="http://localhost:8000")
# Create a conversation
conv = await client.conversations.create(
tenant_name="acme-corp",
user_id="user-123",
title="Async Support Session"
)
# Add messages
msg = await client.messages.create(
conversation_id=conv.id,
role=MessageRole.USER,
content="Hello from async!"
)
# Auto-pagination with async for
async for conversation in client.conversations.list_iter(tenant_name="acme-corp"):
print(f"Conversation: {conversation.title}")
# Search conversations
results = await client.conversations.search(
q="support",
status=ConversationStatus.ACTIVE
)
# Archive when done
await client.conversations.archive(conv.id)
asyncio.run(main())
Async Context Manager
async with AsyncMarchHistoryClient(base_url="http://localhost:8000") as client:
conv = await client.conversations.create(
tenant_name="acme-corp",
user_id="user-123",
title="Chat"
)
# Connections automatically closed
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:
- basic_usage.py - Complete workflow example
- pagination_example.py - Pagination patterns
- error_handling.py - Error handling strategies
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:
- GitHub Issues: https://github.com/march/march-history-sdk/issues
- Documentation: https://github.com/march/march-history-sdk#readme
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file march_history-0.2.2.tar.gz.
File metadata
- Download URL: march_history-0.2.2.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b854becb795d693dd8936b6e33078a857a3e1e7e5013c20825a858422618b523
|
|
| MD5 |
78fda8ee7a0e9da17fea8595a95d7d0e
|
|
| BLAKE2b-256 |
80e238f361c342bc615e4dbb28ab51576f23f8c818c9a0ebca54343a41cab79c
|
File details
Details for the file march_history-0.2.2-py3-none-any.whl.
File metadata
- Download URL: march_history-0.2.2-py3-none-any.whl
- Upload date:
- Size: 35.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75c5dc126665d42ab56c149f427d896cc5f9998ca47508e2dd3a9a0f08105350
|
|
| MD5 |
523998681459b5aed7360737dad2ddf5
|
|
| BLAKE2b-256 |
adb241b98126054ae9a509fd8762bd256e98b850c0f909f76cbf7e902984c77c
|