Skip to content

tracemem/tracemem-py

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tracemem

Python SDK for TraceMem - Decision tracking and traceability for AI agents and automation systems.

Quick Start (60 seconds)

import asyncio
import os
from tracemem import TraceMemClient

async def main():
    # Create client (only api_key required)
    client = TraceMemClient(api_key=os.getenv("TRACEMEM_API_KEY"))
    
    # Open a decision from an action
    decision = await client.open("refactor", {
        "automation_mode": "propose",
    })
    
    # Add context
    await decision.note({
        "kind": "info",
        "message": "Starting refactoring work",
    })
    
    # Close the decision
    await decision.close({
        "outcome": "commit",
        "reason": "Refactoring completed successfully",
    })
    
    # Clean up
    await client.close_session()

asyncio.run(main())

Installation

pip install tracemem

Configuration

The SDK requires only an API key to get started:

from tracemem import TraceMemClient

client = TraceMemClient(api_key="your-api-key-here")

Optional Configuration

client = TraceMemClient(
    api_key="your-api-key-here",
    mcp_url="https://mcp.tracemem.com",  # Default
    timeout_ms=30000,  # Default: 30 seconds
    sanitize=True,  # Default: true (redacts secrets, truncates large data)
    default_actor="my-agent",  # Default: "tracemem-py"
    default_automation_mode="propose",  # Default: "propose"
    action_intent_map={  # Extend default action->intent mapping
        "custom_action": "custom.intent.execute",
    },
)

Decision Lifecycle

Opening a Decision

Use open() to create a decision from a common action (automatically maps to intent):

decision = await client.open("edit_files", {
    "automation_mode": "propose",
    "actor": "my-agent",
    "metadata": {
        "project": "my-project",
        "branch": "main",
    },
})

Creating a Decision with Explicit Intent

Use create_decision() for explicit intent control:

decision = await client.create_decision("code.change.apply", {
    "automation_mode": "execute",
    "actor": "my-agent",
    "instance": "instance-123",
    "version": "1.0.0",
    "metadata": {
        "custom": "data",
    },
})

Adding Context/Notes

await decision.note({
    "kind": "info",
    "message": "Starting work",
    "data": {
        "files": ["file1.py", "file2.py"],
    },
})

Reading from Data Products

result = await decision.read("pg_customers_v1", "order_validation", {
    "query": {
        "customer_id": "12345",
    },
    "result_mode": "single",  # or "multiple"
})

Evaluating Policies

evaluation = await decision.evaluate("discount_cap_v1", {
    "inputs": {
        "proposed_discount": 0.15,
        "customer_tier": "premium",
    },
})

Requesting Approval

await decision.request_approval({
    "kind": "discount_approval",
    "message": "Customer requesting 25% discount, exceeds policy limit",
})

Writing to Data Products

await decision.write("pg_orders_v1", "order_creation", {
    "operation": "insert",
    "records": [
        {
            "order_id": "ord_123",
            "customer_id": "cust_456",
            "amount": 99.99,
        },
    ],
}, {
    "idempotency_key": "order_123_unique",
})

Getting Trace and Receipt

# Get full trace of decision activities
trace = await decision.trace()

# Get receipt (summary)
receipt = await decision.receipt()

Closing a Decision

await decision.close({
    "outcome": "commit",  # or "abort"
    "reason": "Order successfully processed",
})

Approvals Example

decision = await client.open("secrets", {
    "automation_mode": "propose",
})

# Evaluate policy
evaluation = await decision.evaluate("secrets_change_policy", {
    "inputs": {
        "secret_name": "DATABASE_PASSWORD",
        "change_type": "update",
    },
})

# Request approval if needed
if evaluation.get("requiresApproval"):
    await decision.request_approval({
        "kind": "secrets_change",
        "message": "Updating production database password",
    })
    
    # Wait for approval (poll or webhook)
    # ... approval logic ...

# Proceed with change
await decision.write("secrets_v1", "secret_update", {
    "operation": "update",
    "name": "DATABASE_PASSWORD",
    "value": "new-secure-password",
})

await decision.close({
    "outcome": "commit",
    "reason": "Secret updated after approval",
})

Product Discovery

# List all products
products_text = await client.products.list()
# Parse JSON if needed
import json
products = json.loads(products_text)

# Get specific product
product_text = await client.products.get("pg_customers_v1")
product = json.loads(product_text)

Using Client Methods Directly

You can also use client methods directly (useful when working with multiple decisions):

decision_id = "dec_abc123"

await client.note(decision_id, {
    "kind": "info",
    "message": "Note",
})

result = await client.read(decision_id, {
    "product": "pg_customers_v1",
    "purpose": "order_validation",
    "query": {"customer_id": "123"},
})

Security and Data Sanitization

By default, the SDK automatically sanitizes data before sending to TraceMem:

  • Secret Redaction: Keys matching patterns like password, api_key, token, secret, etc. are redacted
  • String Truncation: Strings longer than 1000 characters are truncated
  • Array Truncation: Arrays longer than 100 items are truncated
  • Object Key Limits: Objects with more than 100 keys are truncated
  • Depth Limits: Nested structures deeper than 10 levels are truncated

To disable sanitization:

client = TraceMemClient(
    api_key="your-key",
    sanitize=False,  # Disable sanitization
)

Note: Disabling sanitization may expose sensitive data. Use with caution.

Error Handling

The SDK provides typed error classes:

from tracemem import (
    TraceMemError,
    TraceMemNetworkError,
    TraceMemValidationError,
    TraceMemTimeoutError,
)

try:
    await client.create_decision("code.change.apply")
except TraceMemNetworkError as e:
    # Handle network error
    print(f"Network error: {e.message}")
except TraceMemValidationError as e:
    # Handle validation error
    print(f"Validation error: {e.message}")
except TraceMemTimeoutError as e:
    # Handle timeout
    print(f"Request timed out: {e.message}")
except TraceMemError as e:
    # Handle other TraceMem errors
    print(f"TraceMem error: {e.code} - {e.message}")

Action to Intent Mapping

The SDK automatically maps common actions to intents:

Action Intent
edit_files code.change.apply
refactor code.refactor.execute
run_command ops.command.execute
deploy deploy.release.execute
secrets secrets.change.propose
db_change data.change.apply
review code.review.assist

Unknown actions are used as-is (no mapping).

Context Manager Support

The client supports async context managers for automatic cleanup:

async with TraceMemClient(api_key="your-key") as client:
    decision = await client.open("refactor")
    # ... work with decision ...
    await decision.close()
# Session automatically closed

Type Hints Support

The SDK is fully typed and includes type hints for all public APIs. It supports Python 3.8+ type hints with the typing module.

Requirements

  • Python >= 3.8
  • aiohttp >= 3.8.0
  • typing-extensions >= 4.0.0 (for Python < 3.11)

Development

Running Tests

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

# Run tests
pytest

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

# Run integration tests (requires API key)
export TRACEMEM_API_KEY="your-api-key"
pytest tests/integration/

Code Quality

# Format code
black tracemem tests

# Lint code
ruff check tracemem tests

# Type check
mypy tracemem

License

Apache-2.0

Links

About

Python SDK for TraceMem - Decision tracking and traceability for AI agents and automation systems

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages