Metadata-Version: 2.4
Name: cmpnd
Version: 0.2.0
Summary: DSPy observability and deployment SDK for cmpnd
Project-URL: Homepage, https://cmpnd.ai
Author-email: cmpnd <hello@cmpnd.io>
License: MIT
Keywords: dspy,llm,observability,tracing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: dspy>=3.1.3
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0
Requires-Dist: xxhash>=3.0.0
Provides-Extra: dev
Requires-Dist: jsonschema>=4.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Provides-Extra: stub
Requires-Dist: cmpnd-deploy; (python_version >= '3.11') and extra == 'stub'
Requires-Dist: fastapi>=0.110; extra == 'stub'
Requires-Dist: python-multipart>=0.0.9; extra == 'stub'
Requires-Dist: uvicorn[standard]>=0.27; extra == 'stub'
Description-Content-Type: text/markdown

# cmpnd

DSPy observability and deployment SDK for cmpnd.

Automatically trace your DSPy programs with one line of code, and deploy them with one more.

## Installation

```bash
pip install cmpnd
```

## Quick Start

```python
import cmpnd

# Configure with your API key
cmpnd.configure(api_key="ct_xxx", project="my-project")

# Enable automatic DSPy instrumentation
cmpnd.auto_instrument()

# Your DSPy code is now automatically traced!
import dspy

lm = dspy.LM("openai/gpt-4o-mini")
dspy.configure(lm=lm)

cot = dspy.ChainOfThought("question -> answer")
result = cot(question="What is DSPy?")
# Trace is automatically sent to cmpnd
```

## Configuration

### Using environment variables

```bash
export CMPND_API_KEY="ct_your_api_key"
export CMPND_ENDPOINT="https://platform.cmpnd.ai"  # optional
```

```python
import cmpnd

cmpnd.configure()  # Reads from environment
cmpnd.auto_instrument()
```

### Configuration options

```python
cmpnd.configure(
    api_key="ct_xxx",                # Required: API key
    endpoint="https://platform.cmpnd.ai", # Optional: Backend URL
    project="my-project",            # Optional: Project name
    batch_size=100,                  # Optional: Batch size for export
    flush_interval_seconds=5.0,      # Optional: Flush interval
    capture_inputs=True,             # Optional: Capture function inputs
    capture_outputs=True,            # Optional: Capture function outputs
    default_tags={"env": "prod"},    # Optional: Tags for all traces
)
```

## Deployment

Deploy a DSPy module to the cmpnd platform for server-side execution:

```python
import cmpnd
import dspy

cmpnd.configure(api_key="ct_xxx")

lm = dspy.LM("groq/llama-3.1-8b-instant", temperature=0.0, max_tokens=16384)
dspy.configure(lm=lm)

module = dspy.Predict("question -> answer")
deployment_id = cmpnd.deploy(module)
```

The SDK packages the module's source code into a ZIP, uploads it to the platform, and polls until the server-side parser finishes. Returns a `deployment_id` for future use with `cmpnd.execute()` (coming soon).

### With a metric (for optimization)

```python
def accuracy(example, pred, trace=None):
    return example.answer == pred.answer

deployment_id = cmpnd.deploy(module, metric=accuracy)
```

### Options

```python
cmpnd.deploy(
    module,              # Required: a DSPy module
    metric=None,         # Optional: metric callable for optimization support
    timeout=300,         # Optional: seconds to wait for parsing (default 300)
)
```

### How it works

1. The SDK generates source code from the live module (LM config, signature, types)
2. `POST /api/v1/deployments` creates a deployment and returns a presigned S3 upload URL
3. The source ZIP is uploaded directly to S3
4. The server-side parser extracts the program and LM configuration
5. The SDK polls until status is `ready`, then returns the `deployment_id`

The deployed program's LM model string (e.g. `groq/llama-3.1-8b-instant`) and configuration (temperature, max_tokens) are extracted automatically from the source.

## Custom Spans

Add custom spans to trace non-DSPy code:

### Using the decorator

```python
from cmpnd import trace, SpanType

@trace(name="fetch_documents", span_type=SpanType.RETRIEVE)
def fetch_documents(query: str) -> list[str]:
    # Your retrieval logic
    return documents
```

### Using the context manager

```python
from cmpnd import start_span, SpanType

def run_pipeline(query: str):
    with start_span("vector_search", span_type=SpanType.RETRIEVE) as span:
        span.set_attribute("index", "my-faiss-index")
        docs = search(query)
        span.set_outputs({"doc_count": len(docs)})

    return generate(query, docs)
```

## What Gets Traced

The SDK automatically captures:

### Module Execution
- Module type (Predict, ChainOfThought, ReAct, etc.)
- Signature name and instructions
- Input/output field names
- Demo count

### LM Calls
- Model name and provider
- Token usage (prompt, completion, total)
- Request/response content

### Adapters
- Format and parse operations
- Input/output transformations

### Tools
- Tool name and description
- Invocation inputs/outputs

### Evaluations
- Evaluation scores
- Program being evaluated

## Span Types

Available span types for categorization:

- `SpanType.MODULE` - Generic DSPy module
- `SpanType.PREDICT` - Predict module
- `SpanType.CHAIN_OF_THOUGHT` - ChainOfThought module
- `SpanType.REACT` - ReAct agent
- `SpanType.RETRIEVE` - Retrieval operations
- `SpanType.LM_CALL` - Language model calls
- `SpanType.ADAPTER_FORMAT` - Adapter formatting
- `SpanType.ADAPTER_PARSE` - Adapter parsing
- `SpanType.TOOL` - Tool invocations
- `SpanType.EVALUATION` - Evaluation runs

## API Reference

### `cmpnd.configure()`

Initialize the SDK with your API key and options.

### `cmpnd.auto_instrument()`

Automatically register the callback with DSPy.

### `cmpnd.CmpndCallback`

The callback class for manual registration:

```python
import dspy
import cmpnd

cmpnd.configure(api_key="ct_xxx")
dspy.configure(callbacks=[cmpnd.CmpndCallback()])
```

### `cmpnd.deploy()`

Deploy a DSPy module to the cmpnd platform. Returns the `deployment_id`.

### `cmpnd.trace()`

Decorator for custom traced functions.

### `cmpnd.start_span()`

Context manager for custom spans.

### `cmpnd.get_current_trace()`

Get the current trace (if any).

### `cmpnd.get_current_span()`

Get the current span (if any).

### `cmpnd.shutdown_exporter()`

Gracefully shutdown the background exporter.

## License

MIT
