cmpnd 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmpnd-0.2.0/.gitignore +43 -0
- cmpnd-0.2.0/CLAUDE.md +24 -0
- cmpnd-0.2.0/PKG-INFO +269 -0
- cmpnd-0.2.0/README.md +233 -0
- cmpnd-0.2.0/cmpnd/__init__.py +338 -0
- cmpnd-0.2.0/cmpnd/callback.py +985 -0
- cmpnd-0.2.0/cmpnd/cli/__init__.py +132 -0
- cmpnd-0.2.0/cmpnd/cli/api_client.py +87 -0
- cmpnd-0.2.0/cmpnd/cli/commands/auth.py +19 -0
- cmpnd-0.2.0/cmpnd/cli/commands/datasets.py +31 -0
- cmpnd-0.2.0/cmpnd/cli/commands/deployments.py +58 -0
- cmpnd-0.2.0/cmpnd/cli/commands/evals.py +42 -0
- cmpnd-0.2.0/cmpnd/cli/commands/optimizations.py +60 -0
- cmpnd-0.2.0/cmpnd/cli/commands/programs.py +55 -0
- cmpnd-0.2.0/cmpnd/cli/commands/top.py +676 -0
- cmpnd-0.2.0/cmpnd/cli/commands/traces.py +63 -0
- cmpnd-0.2.0/cmpnd/config.py +160 -0
- cmpnd-0.2.0/cmpnd/context.py +118 -0
- cmpnd-0.2.0/cmpnd/dataset_sync.py +128 -0
- cmpnd-0.2.0/cmpnd/datasets.py +219 -0
- cmpnd-0.2.0/cmpnd/decorators.py +144 -0
- cmpnd-0.2.0/cmpnd/deploy.py +212 -0
- cmpnd-0.2.0/cmpnd/eval_handler.py +384 -0
- cmpnd-0.2.0/cmpnd/execute.py +132 -0
- cmpnd-0.2.0/cmpnd/exporter.py +601 -0
- cmpnd-0.2.0/cmpnd/helpers.py +220 -0
- cmpnd-0.2.0/cmpnd/identity.py +433 -0
- cmpnd-0.2.0/cmpnd/models.py +755 -0
- cmpnd-0.2.0/cmpnd/optimizers/__init__.py +31 -0
- cmpnd-0.2.0/cmpnd/optimizers/gepa.py +390 -0
- cmpnd-0.2.0/cmpnd/optimizers/gepa_callback.py +472 -0
- cmpnd-0.2.0/cmpnd/optimizers/tracker.py +903 -0
- cmpnd-0.2.0/cmpnd/packaging.py +331 -0
- cmpnd-0.2.0/docs/2026-04-02-code-review.md +280 -0
- cmpnd-0.2.0/docs/plans/2026-04-05-train-val-dataset-capture-design.md +91 -0
- cmpnd-0.2.0/docs/plans/2026-04-05-train-val-dataset-capture.md +727 -0
- cmpnd-0.2.0/examples/local_ollama.py +40 -0
- cmpnd-0.2.0/pyproject.toml +90 -0
- cmpnd-0.2.0/tests/__init__.py +1 -0
- cmpnd-0.2.0/tests/e2e/__init__.py +0 -0
- cmpnd-0.2.0/tests/e2e/conftest.py +280 -0
- cmpnd-0.2.0/tests/e2e/test_capture_prompts.py +129 -0
- cmpnd-0.2.0/tests/e2e/test_composite_module.py +86 -0
- cmpnd-0.2.0/tests/e2e/test_dataset_auto_creation.py +271 -0
- cmpnd-0.2.0/tests/e2e/test_deploy_execute.py +311 -0
- cmpnd-0.2.0/tests/e2e/test_edge_cases.py +62 -0
- cmpnd-0.2.0/tests/e2e/test_example_hash.py +150 -0
- cmpnd-0.2.0/tests/e2e/test_gepa_optimization.py +92 -0
- cmpnd-0.2.0/tests/e2e/test_lm_accuracy.py +99 -0
- cmpnd-0.2.0/tests/e2e/test_module_tracing.py +205 -0
- cmpnd-0.2.0/tests/e2e/test_optimization_metric_identity.py +111 -0
- cmpnd-0.2.0/tests/e2e/test_parallel_export.py +104 -0
- cmpnd-0.2.0/tests/e2e/test_project_attribution.py +147 -0
- cmpnd-0.2.0/tests/e2e/test_react_tool_spans.py +79 -0
- cmpnd-0.2.0/tests/e2e/test_span_thinning.py +67 -0
- cmpnd-0.2.0/tests/e2e/test_trace_structure.py +180 -0
- cmpnd-0.2.0/tests/e2e/test_user_attribution.py +181 -0
- cmpnd-0.2.0/tests/integration/__init__.py +0 -0
- cmpnd-0.2.0/tests/integration/conftest.py +76 -0
- cmpnd-0.2.0/tests/integration/test_cli_deploy_smoketest.py +124 -0
- cmpnd-0.2.0/tests/integration/test_logs_renders_traces.py +152 -0
- cmpnd-0.2.0/tests/integration/test_optimizing_progress.py +135 -0
- cmpnd-0.2.0/tests/integration/test_unhappy_path.py +196 -0
- cmpnd-0.2.0/tests/test_callback.py +1856 -0
- cmpnd-0.2.0/tests/test_cli/__init__.py +0 -0
- cmpnd-0.2.0/tests/test_cli/conftest.py +15 -0
- cmpnd-0.2.0/tests/test_cli/test_api_client.py +123 -0
- cmpnd-0.2.0/tests/test_cli/test_auth.py +16 -0
- cmpnd-0.2.0/tests/test_cli/test_datasets.py +23 -0
- cmpnd-0.2.0/tests/test_cli/test_deployments.py +51 -0
- cmpnd-0.2.0/tests/test_cli/test_evals.py +33 -0
- cmpnd-0.2.0/tests/test_cli/test_main.py +44 -0
- cmpnd-0.2.0/tests/test_cli/test_optimizations.py +52 -0
- cmpnd-0.2.0/tests/test_cli/test_programs.py +50 -0
- cmpnd-0.2.0/tests/test_cli/test_top.py +480 -0
- cmpnd-0.2.0/tests/test_cli/test_traces.py +51 -0
- cmpnd-0.2.0/tests/test_clustering/__init__.py +6 -0
- cmpnd-0.2.0/tests/test_clustering/conftest.py +153 -0
- cmpnd-0.2.0/tests/test_clustering/test_edge_cases.py +324 -0
- cmpnd-0.2.0/tests/test_clustering/test_hash_consistency.py +265 -0
- cmpnd-0.2.0/tests/test_clustering/test_type_conversion.py +214 -0
- cmpnd-0.2.0/tests/test_config.py +178 -0
- cmpnd-0.2.0/tests/test_context.py +226 -0
- cmpnd-0.2.0/tests/test_context_propagation.py +49 -0
- cmpnd-0.2.0/tests/test_dataset_sync.py +497 -0
- cmpnd-0.2.0/tests/test_datasets.py +568 -0
- cmpnd-0.2.0/tests/test_decorators.py +302 -0
- cmpnd-0.2.0/tests/test_deploy.py +279 -0
- cmpnd-0.2.0/tests/test_eval.py +564 -0
- cmpnd-0.2.0/tests/test_exception_paths.py +302 -0
- cmpnd-0.2.0/tests/test_execute.py +160 -0
- cmpnd-0.2.0/tests/test_exporter.py +428 -0
- cmpnd-0.2.0/tests/test_exporter_real.py +461 -0
- cmpnd-0.2.0/tests/test_gepa_callback.py +1743 -0
- cmpnd-0.2.0/tests/test_gepa_integration.py +241 -0
- cmpnd-0.2.0/tests/test_identity.py +476 -0
- cmpnd-0.2.0/tests/test_integration.py +397 -0
- cmpnd-0.2.0/tests/test_models.py +457 -0
- cmpnd-0.2.0/tests/test_packaging.py +179 -0
- cmpnd-0.2.0/tests/test_project_payload.py +147 -0
- cmpnd-0.2.0/tests/test_repro_reactv2_bugs.py +195 -0
- cmpnd-0.2.0/tests/test_schemas.py +132 -0
- cmpnd-0.2.0/tests/test_span_thinning.py +183 -0
- cmpnd-0.2.0/tests/test_stats_export.py +118 -0
- cmpnd-0.2.0/tests/test_tracked_gepa.py +1015 -0
- cmpnd-0.2.0/tests/test_truncation.py +167 -0
- cmpnd-0.2.0/todo.md +45 -0
- cmpnd-0.2.0/uv.lock +3276 -0
- cmpnd-0.1.0/PKG-INFO +0 -6
- cmpnd-0.1.0/cmpnd.egg-info/PKG-INFO +0 -6
- cmpnd-0.1.0/cmpnd.egg-info/SOURCES.txt +0 -7
- cmpnd-0.1.0/cmpnd.egg-info/dependency_links.txt +0 -1
- cmpnd-0.1.0/cmpnd.egg-info/top_level.txt +0 -1
- cmpnd-0.1.0/main.py +0 -6
- cmpnd-0.1.0/pyproject.toml +0 -7
- cmpnd-0.1.0/setup.cfg +0 -4
- /cmpnd-0.1.0/README.md → /cmpnd-0.2.0/cmpnd/cli/commands/__init__.py +0 -0
cmpnd-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
parts/
|
|
14
|
+
sdist/
|
|
15
|
+
var/
|
|
16
|
+
wheels/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
.installed.cfg
|
|
19
|
+
*.egg
|
|
20
|
+
|
|
21
|
+
# Virtual environments
|
|
22
|
+
.env
|
|
23
|
+
.venv
|
|
24
|
+
env/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
|
|
34
|
+
# Testing
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.coverage
|
|
37
|
+
htmlcov/
|
|
38
|
+
.tox/
|
|
39
|
+
.nox/
|
|
40
|
+
|
|
41
|
+
# Misc
|
|
42
|
+
*.log
|
|
43
|
+
.DS_Store
|
cmpnd-0.2.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Claude Code Instructions
|
|
2
|
+
|
|
3
|
+
Part of the CMPND monorepo. See `../CLAUDE.md` for cross-cutting rules (hash architecture, null handling, testing philosophy).
|
|
4
|
+
|
|
5
|
+
## Running Tests & Checks
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m pytest tests/ # all tests (excluding e2e)
|
|
9
|
+
python -m pytest tests/ -k "not e2e" # skip e2e explicitly
|
|
10
|
+
ruff check . # lint
|
|
11
|
+
ruff format --check . # format check
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Key Files
|
|
15
|
+
|
|
16
|
+
- `cmpnd/identity.py` - Unified hash computations (xxhash, SHA256)
|
|
17
|
+
- `cmpnd/callback.py` - DSPy instrumentation, signature extraction
|
|
18
|
+
- `cmpnd/optimizers/tracker.py` - Optimization tracking
|
|
19
|
+
- `cmpnd/packaging.py` - Source ZIP generation for deploy (ported from deploy/local_cmpnd.py)
|
|
20
|
+
- `cmpnd/deploy.py` - `deploy()` function: SDK -> Rails -> AWS deploy stack
|
|
21
|
+
|
|
22
|
+
## Release
|
|
23
|
+
|
|
24
|
+
See the "PyPI SDK release" section in [`docs/deployment.md`](../docs/deployment.md). Short version: `git tag sdk-v<version> && git push origin sdk-v<version>`. Version is derived from the git tag at build time (dynamic versioning).
|
cmpnd-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cmpnd
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: DSPy observability and deployment SDK for cmpnd
|
|
5
|
+
Project-URL: Homepage, https://cmpnd.ai
|
|
6
|
+
Author-email: cmpnd <hello@cmpnd.io>
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: dspy,llm,observability,tracing
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: dspy>=3.1.3
|
|
21
|
+
Requires-Dist: httpx>=0.27.0
|
|
22
|
+
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: xxhash>=3.0.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: jsonschema>=4.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: stub
|
|
31
|
+
Requires-Dist: cmpnd-deploy; (python_version >= '3.11') and extra == 'stub'
|
|
32
|
+
Requires-Dist: fastapi>=0.110; extra == 'stub'
|
|
33
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'stub'
|
|
34
|
+
Requires-Dist: uvicorn[standard]>=0.27; extra == 'stub'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# cmpnd
|
|
38
|
+
|
|
39
|
+
DSPy observability and deployment SDK for cmpnd.
|
|
40
|
+
|
|
41
|
+
Automatically trace your DSPy programs with one line of code, and deploy them with one more.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install cmpnd
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import cmpnd
|
|
53
|
+
|
|
54
|
+
# Configure with your API key
|
|
55
|
+
cmpnd.configure(api_key="ct_xxx", project="my-project")
|
|
56
|
+
|
|
57
|
+
# Enable automatic DSPy instrumentation
|
|
58
|
+
cmpnd.auto_instrument()
|
|
59
|
+
|
|
60
|
+
# Your DSPy code is now automatically traced!
|
|
61
|
+
import dspy
|
|
62
|
+
|
|
63
|
+
lm = dspy.LM("openai/gpt-4o-mini")
|
|
64
|
+
dspy.configure(lm=lm)
|
|
65
|
+
|
|
66
|
+
cot = dspy.ChainOfThought("question -> answer")
|
|
67
|
+
result = cot(question="What is DSPy?")
|
|
68
|
+
# Trace is automatically sent to cmpnd
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
### Using environment variables
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export CMPND_API_KEY="ct_your_api_key"
|
|
77
|
+
export CMPND_ENDPOINT="https://platform.cmpnd.ai" # optional
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import cmpnd
|
|
82
|
+
|
|
83
|
+
cmpnd.configure() # Reads from environment
|
|
84
|
+
cmpnd.auto_instrument()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Configuration options
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
cmpnd.configure(
|
|
91
|
+
api_key="ct_xxx", # Required: API key
|
|
92
|
+
endpoint="https://platform.cmpnd.ai", # Optional: Backend URL
|
|
93
|
+
project="my-project", # Optional: Project name
|
|
94
|
+
batch_size=100, # Optional: Batch size for export
|
|
95
|
+
flush_interval_seconds=5.0, # Optional: Flush interval
|
|
96
|
+
capture_inputs=True, # Optional: Capture function inputs
|
|
97
|
+
capture_outputs=True, # Optional: Capture function outputs
|
|
98
|
+
default_tags={"env": "prod"}, # Optional: Tags for all traces
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Deployment
|
|
103
|
+
|
|
104
|
+
Deploy a DSPy module to the cmpnd platform for server-side execution:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import cmpnd
|
|
108
|
+
import dspy
|
|
109
|
+
|
|
110
|
+
cmpnd.configure(api_key="ct_xxx")
|
|
111
|
+
|
|
112
|
+
lm = dspy.LM("groq/llama-3.1-8b-instant", temperature=0.0, max_tokens=16384)
|
|
113
|
+
dspy.configure(lm=lm)
|
|
114
|
+
|
|
115
|
+
module = dspy.Predict("question -> answer")
|
|
116
|
+
deployment_id = cmpnd.deploy(module)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
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).
|
|
120
|
+
|
|
121
|
+
### With a metric (for optimization)
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
def accuracy(example, pred, trace=None):
|
|
125
|
+
return example.answer == pred.answer
|
|
126
|
+
|
|
127
|
+
deployment_id = cmpnd.deploy(module, metric=accuracy)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Options
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
cmpnd.deploy(
|
|
134
|
+
module, # Required: a DSPy module
|
|
135
|
+
metric=None, # Optional: metric callable for optimization support
|
|
136
|
+
timeout=300, # Optional: seconds to wait for parsing (default 300)
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### How it works
|
|
141
|
+
|
|
142
|
+
1. The SDK generates source code from the live module (LM config, signature, types)
|
|
143
|
+
2. `POST /api/v1/deployments` creates a deployment and returns a presigned S3 upload URL
|
|
144
|
+
3. The source ZIP is uploaded directly to S3
|
|
145
|
+
4. The server-side parser extracts the program and LM configuration
|
|
146
|
+
5. The SDK polls until status is `ready`, then returns the `deployment_id`
|
|
147
|
+
|
|
148
|
+
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.
|
|
149
|
+
|
|
150
|
+
## Custom Spans
|
|
151
|
+
|
|
152
|
+
Add custom spans to trace non-DSPy code:
|
|
153
|
+
|
|
154
|
+
### Using the decorator
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from cmpnd import trace, SpanType
|
|
158
|
+
|
|
159
|
+
@trace(name="fetch_documents", span_type=SpanType.RETRIEVE)
|
|
160
|
+
def fetch_documents(query: str) -> list[str]:
|
|
161
|
+
# Your retrieval logic
|
|
162
|
+
return documents
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Using the context manager
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from cmpnd import start_span, SpanType
|
|
169
|
+
|
|
170
|
+
def run_pipeline(query: str):
|
|
171
|
+
with start_span("vector_search", span_type=SpanType.RETRIEVE) as span:
|
|
172
|
+
span.set_attribute("index", "my-faiss-index")
|
|
173
|
+
docs = search(query)
|
|
174
|
+
span.set_outputs({"doc_count": len(docs)})
|
|
175
|
+
|
|
176
|
+
return generate(query, docs)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## What Gets Traced
|
|
180
|
+
|
|
181
|
+
The SDK automatically captures:
|
|
182
|
+
|
|
183
|
+
### Module Execution
|
|
184
|
+
- Module type (Predict, ChainOfThought, ReAct, etc.)
|
|
185
|
+
- Signature name and instructions
|
|
186
|
+
- Input/output field names
|
|
187
|
+
- Demo count
|
|
188
|
+
|
|
189
|
+
### LM Calls
|
|
190
|
+
- Model name and provider
|
|
191
|
+
- Token usage (prompt, completion, total)
|
|
192
|
+
- Request/response content
|
|
193
|
+
|
|
194
|
+
### Adapters
|
|
195
|
+
- Format and parse operations
|
|
196
|
+
- Input/output transformations
|
|
197
|
+
|
|
198
|
+
### Tools
|
|
199
|
+
- Tool name and description
|
|
200
|
+
- Invocation inputs/outputs
|
|
201
|
+
|
|
202
|
+
### Evaluations
|
|
203
|
+
- Evaluation scores
|
|
204
|
+
- Program being evaluated
|
|
205
|
+
|
|
206
|
+
## Span Types
|
|
207
|
+
|
|
208
|
+
Available span types for categorization:
|
|
209
|
+
|
|
210
|
+
- `SpanType.MODULE` - Generic DSPy module
|
|
211
|
+
- `SpanType.PREDICT` - Predict module
|
|
212
|
+
- `SpanType.CHAIN_OF_THOUGHT` - ChainOfThought module
|
|
213
|
+
- `SpanType.REACT` - ReAct agent
|
|
214
|
+
- `SpanType.RETRIEVE` - Retrieval operations
|
|
215
|
+
- `SpanType.LM_CALL` - Language model calls
|
|
216
|
+
- `SpanType.ADAPTER_FORMAT` - Adapter formatting
|
|
217
|
+
- `SpanType.ADAPTER_PARSE` - Adapter parsing
|
|
218
|
+
- `SpanType.TOOL` - Tool invocations
|
|
219
|
+
- `SpanType.EVALUATION` - Evaluation runs
|
|
220
|
+
|
|
221
|
+
## API Reference
|
|
222
|
+
|
|
223
|
+
### `cmpnd.configure()`
|
|
224
|
+
|
|
225
|
+
Initialize the SDK with your API key and options.
|
|
226
|
+
|
|
227
|
+
### `cmpnd.auto_instrument()`
|
|
228
|
+
|
|
229
|
+
Automatically register the callback with DSPy.
|
|
230
|
+
|
|
231
|
+
### `cmpnd.CmpndCallback`
|
|
232
|
+
|
|
233
|
+
The callback class for manual registration:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
import dspy
|
|
237
|
+
import cmpnd
|
|
238
|
+
|
|
239
|
+
cmpnd.configure(api_key="ct_xxx")
|
|
240
|
+
dspy.configure(callbacks=[cmpnd.CmpndCallback()])
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### `cmpnd.deploy()`
|
|
244
|
+
|
|
245
|
+
Deploy a DSPy module to the cmpnd platform. Returns the `deployment_id`.
|
|
246
|
+
|
|
247
|
+
### `cmpnd.trace()`
|
|
248
|
+
|
|
249
|
+
Decorator for custom traced functions.
|
|
250
|
+
|
|
251
|
+
### `cmpnd.start_span()`
|
|
252
|
+
|
|
253
|
+
Context manager for custom spans.
|
|
254
|
+
|
|
255
|
+
### `cmpnd.get_current_trace()`
|
|
256
|
+
|
|
257
|
+
Get the current trace (if any).
|
|
258
|
+
|
|
259
|
+
### `cmpnd.get_current_span()`
|
|
260
|
+
|
|
261
|
+
Get the current span (if any).
|
|
262
|
+
|
|
263
|
+
### `cmpnd.shutdown_exporter()`
|
|
264
|
+
|
|
265
|
+
Gracefully shutdown the background exporter.
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
MIT
|
cmpnd-0.2.0/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# cmpnd
|
|
2
|
+
|
|
3
|
+
DSPy observability and deployment SDK for cmpnd.
|
|
4
|
+
|
|
5
|
+
Automatically trace your DSPy programs with one line of code, and deploy them with one more.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install cmpnd
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import cmpnd
|
|
17
|
+
|
|
18
|
+
# Configure with your API key
|
|
19
|
+
cmpnd.configure(api_key="ct_xxx", project="my-project")
|
|
20
|
+
|
|
21
|
+
# Enable automatic DSPy instrumentation
|
|
22
|
+
cmpnd.auto_instrument()
|
|
23
|
+
|
|
24
|
+
# Your DSPy code is now automatically traced!
|
|
25
|
+
import dspy
|
|
26
|
+
|
|
27
|
+
lm = dspy.LM("openai/gpt-4o-mini")
|
|
28
|
+
dspy.configure(lm=lm)
|
|
29
|
+
|
|
30
|
+
cot = dspy.ChainOfThought("question -> answer")
|
|
31
|
+
result = cot(question="What is DSPy?")
|
|
32
|
+
# Trace is automatically sent to cmpnd
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Configuration
|
|
36
|
+
|
|
37
|
+
### Using environment variables
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export CMPND_API_KEY="ct_your_api_key"
|
|
41
|
+
export CMPND_ENDPOINT="https://platform.cmpnd.ai" # optional
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import cmpnd
|
|
46
|
+
|
|
47
|
+
cmpnd.configure() # Reads from environment
|
|
48
|
+
cmpnd.auto_instrument()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Configuration options
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
cmpnd.configure(
|
|
55
|
+
api_key="ct_xxx", # Required: API key
|
|
56
|
+
endpoint="https://platform.cmpnd.ai", # Optional: Backend URL
|
|
57
|
+
project="my-project", # Optional: Project name
|
|
58
|
+
batch_size=100, # Optional: Batch size for export
|
|
59
|
+
flush_interval_seconds=5.0, # Optional: Flush interval
|
|
60
|
+
capture_inputs=True, # Optional: Capture function inputs
|
|
61
|
+
capture_outputs=True, # Optional: Capture function outputs
|
|
62
|
+
default_tags={"env": "prod"}, # Optional: Tags for all traces
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Deployment
|
|
67
|
+
|
|
68
|
+
Deploy a DSPy module to the cmpnd platform for server-side execution:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import cmpnd
|
|
72
|
+
import dspy
|
|
73
|
+
|
|
74
|
+
cmpnd.configure(api_key="ct_xxx")
|
|
75
|
+
|
|
76
|
+
lm = dspy.LM("groq/llama-3.1-8b-instant", temperature=0.0, max_tokens=16384)
|
|
77
|
+
dspy.configure(lm=lm)
|
|
78
|
+
|
|
79
|
+
module = dspy.Predict("question -> answer")
|
|
80
|
+
deployment_id = cmpnd.deploy(module)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
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).
|
|
84
|
+
|
|
85
|
+
### With a metric (for optimization)
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
def accuracy(example, pred, trace=None):
|
|
89
|
+
return example.answer == pred.answer
|
|
90
|
+
|
|
91
|
+
deployment_id = cmpnd.deploy(module, metric=accuracy)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Options
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
cmpnd.deploy(
|
|
98
|
+
module, # Required: a DSPy module
|
|
99
|
+
metric=None, # Optional: metric callable for optimization support
|
|
100
|
+
timeout=300, # Optional: seconds to wait for parsing (default 300)
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### How it works
|
|
105
|
+
|
|
106
|
+
1. The SDK generates source code from the live module (LM config, signature, types)
|
|
107
|
+
2. `POST /api/v1/deployments` creates a deployment and returns a presigned S3 upload URL
|
|
108
|
+
3. The source ZIP is uploaded directly to S3
|
|
109
|
+
4. The server-side parser extracts the program and LM configuration
|
|
110
|
+
5. The SDK polls until status is `ready`, then returns the `deployment_id`
|
|
111
|
+
|
|
112
|
+
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.
|
|
113
|
+
|
|
114
|
+
## Custom Spans
|
|
115
|
+
|
|
116
|
+
Add custom spans to trace non-DSPy code:
|
|
117
|
+
|
|
118
|
+
### Using the decorator
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from cmpnd import trace, SpanType
|
|
122
|
+
|
|
123
|
+
@trace(name="fetch_documents", span_type=SpanType.RETRIEVE)
|
|
124
|
+
def fetch_documents(query: str) -> list[str]:
|
|
125
|
+
# Your retrieval logic
|
|
126
|
+
return documents
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Using the context manager
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from cmpnd import start_span, SpanType
|
|
133
|
+
|
|
134
|
+
def run_pipeline(query: str):
|
|
135
|
+
with start_span("vector_search", span_type=SpanType.RETRIEVE) as span:
|
|
136
|
+
span.set_attribute("index", "my-faiss-index")
|
|
137
|
+
docs = search(query)
|
|
138
|
+
span.set_outputs({"doc_count": len(docs)})
|
|
139
|
+
|
|
140
|
+
return generate(query, docs)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## What Gets Traced
|
|
144
|
+
|
|
145
|
+
The SDK automatically captures:
|
|
146
|
+
|
|
147
|
+
### Module Execution
|
|
148
|
+
- Module type (Predict, ChainOfThought, ReAct, etc.)
|
|
149
|
+
- Signature name and instructions
|
|
150
|
+
- Input/output field names
|
|
151
|
+
- Demo count
|
|
152
|
+
|
|
153
|
+
### LM Calls
|
|
154
|
+
- Model name and provider
|
|
155
|
+
- Token usage (prompt, completion, total)
|
|
156
|
+
- Request/response content
|
|
157
|
+
|
|
158
|
+
### Adapters
|
|
159
|
+
- Format and parse operations
|
|
160
|
+
- Input/output transformations
|
|
161
|
+
|
|
162
|
+
### Tools
|
|
163
|
+
- Tool name and description
|
|
164
|
+
- Invocation inputs/outputs
|
|
165
|
+
|
|
166
|
+
### Evaluations
|
|
167
|
+
- Evaluation scores
|
|
168
|
+
- Program being evaluated
|
|
169
|
+
|
|
170
|
+
## Span Types
|
|
171
|
+
|
|
172
|
+
Available span types for categorization:
|
|
173
|
+
|
|
174
|
+
- `SpanType.MODULE` - Generic DSPy module
|
|
175
|
+
- `SpanType.PREDICT` - Predict module
|
|
176
|
+
- `SpanType.CHAIN_OF_THOUGHT` - ChainOfThought module
|
|
177
|
+
- `SpanType.REACT` - ReAct agent
|
|
178
|
+
- `SpanType.RETRIEVE` - Retrieval operations
|
|
179
|
+
- `SpanType.LM_CALL` - Language model calls
|
|
180
|
+
- `SpanType.ADAPTER_FORMAT` - Adapter formatting
|
|
181
|
+
- `SpanType.ADAPTER_PARSE` - Adapter parsing
|
|
182
|
+
- `SpanType.TOOL` - Tool invocations
|
|
183
|
+
- `SpanType.EVALUATION` - Evaluation runs
|
|
184
|
+
|
|
185
|
+
## API Reference
|
|
186
|
+
|
|
187
|
+
### `cmpnd.configure()`
|
|
188
|
+
|
|
189
|
+
Initialize the SDK with your API key and options.
|
|
190
|
+
|
|
191
|
+
### `cmpnd.auto_instrument()`
|
|
192
|
+
|
|
193
|
+
Automatically register the callback with DSPy.
|
|
194
|
+
|
|
195
|
+
### `cmpnd.CmpndCallback`
|
|
196
|
+
|
|
197
|
+
The callback class for manual registration:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import dspy
|
|
201
|
+
import cmpnd
|
|
202
|
+
|
|
203
|
+
cmpnd.configure(api_key="ct_xxx")
|
|
204
|
+
dspy.configure(callbacks=[cmpnd.CmpndCallback()])
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `cmpnd.deploy()`
|
|
208
|
+
|
|
209
|
+
Deploy a DSPy module to the cmpnd platform. Returns the `deployment_id`.
|
|
210
|
+
|
|
211
|
+
### `cmpnd.trace()`
|
|
212
|
+
|
|
213
|
+
Decorator for custom traced functions.
|
|
214
|
+
|
|
215
|
+
### `cmpnd.start_span()`
|
|
216
|
+
|
|
217
|
+
Context manager for custom spans.
|
|
218
|
+
|
|
219
|
+
### `cmpnd.get_current_trace()`
|
|
220
|
+
|
|
221
|
+
Get the current trace (if any).
|
|
222
|
+
|
|
223
|
+
### `cmpnd.get_current_span()`
|
|
224
|
+
|
|
225
|
+
Get the current span (if any).
|
|
226
|
+
|
|
227
|
+
### `cmpnd.shutdown_exporter()`
|
|
228
|
+
|
|
229
|
+
Gracefully shutdown the background exporter.
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|