cmpnd 0.40.1__tar.gz → 0.42.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.40.1 → cmpnd-0.42.0}/PKG-INFO +8 -7
- {cmpnd-0.40.1 → cmpnd-0.42.0}/README.md +1 -1
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/top.py +14 -21
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/shell.py +4 -4
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/trace_render.py +2 -2
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/deployment.py +40 -18
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimization.py +10 -22
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/packaging.py +2 -2
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/programs.py +17 -1
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/cli.md +9 -4
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/sdk-instrumentation.md +9 -6
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/pyproject.toml +1 -1
- {cmpnd-0.40.1 → cmpnd-0.42.0}/pyproject.toml +17 -18
- cmpnd-0.42.0/scripts/check-pip-install.sh +34 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/require_version_bump.py +2 -11
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/test_unhappy_path.py +1 -2
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/_readiness.py +1 -1
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_shell.py +12 -6
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_top.py +21 -12
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_traces_search_wire.py +2 -4
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deploy_program_id.py +56 -47
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_programs_create.py +15 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_require_version_bump.py +0 -7
- {cmpnd-0.40.1 → cmpnd-0.42.0}/uv.lock +484 -941
- {cmpnd-0.40.1 → cmpnd-0.42.0}/.gitignore +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/AGENTS.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/CLAUDE.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/signatures.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/client.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/context.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/models.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/references.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/client.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/README.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/release-stress.sh +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/drain.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/_provider.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/_reliability.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/_result.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/mint_bedrock_token.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_deploy_programs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_multi_client_stress.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_optimize_client_committee.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_optimize_loop.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_optimize_stress.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_provider_roles.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_readiness.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_real_provider_twins.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_reliability.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_reliability_classify.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_rlm_wasm.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/stress/test_trace_search.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_authored.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_callback.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_signatures.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_client.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_context.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_eval.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_execute.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_integration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_models.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_release_stress_script.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_retry.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.40.1 → cmpnd-0.42.0}/tests/test_xxh64.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cmpnd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.42.0
|
|
4
4
|
Summary: DSPy observability and deployment SDK for cmpnd
|
|
5
5
|
Project-URL: Homepage, https://cmpnd.ai
|
|
6
6
|
Author-email: cmpnd <hello@cmpnd.ai>
|
|
@@ -10,13 +10,13 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
20
|
Requires-Dist: dspy>=3.1.3
|
|
21
21
|
Requires-Dist: httpx>=0.27.0
|
|
22
22
|
Requires-Dist: ipython>=8.20
|
|
@@ -27,10 +27,11 @@ Requires-Dist: xxhash>=3.0.0
|
|
|
27
27
|
Provides-Extra: dev
|
|
28
28
|
Requires-Dist: basedpyright>=1.39; extra == 'dev'
|
|
29
29
|
Requires-Dist: boto3>=1.34; extra == 'dev'
|
|
30
|
+
Requires-Dist: gepa; extra == 'dev'
|
|
30
31
|
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
31
32
|
Requires-Dist: jsonschema>=4.0; extra == 'dev'
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: numpy>=2.3;
|
|
33
|
+
Requires-Dist: litellm; extra == 'dev'
|
|
34
|
+
Requires-Dist: numpy>=2.3; extra == 'dev'
|
|
34
35
|
Requires-Dist: pandas>=2.2; extra == 'dev'
|
|
35
36
|
Requires-Dist: pillow>=10.0; extra == 'dev'
|
|
36
37
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
@@ -40,7 +41,7 @@ Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
|
40
41
|
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
41
42
|
Requires-Dist: twine>=7.0; extra == 'dev'
|
|
42
43
|
Provides-Extra: fake-provider
|
|
43
|
-
Requires-Dist: cmpnd-fake-provider;
|
|
44
|
+
Requires-Dist: cmpnd-fake-provider; extra == 'fake-provider'
|
|
44
45
|
Provides-Extra: images
|
|
45
46
|
Requires-Dist: pillow>=10.0; extra == 'images'
|
|
46
47
|
Provides-Extra: mcp
|
|
@@ -161,7 +162,7 @@ cmpnd.deploy(
|
|
|
161
162
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
162
163
|
timeout=300, # optional: seconds to wait for the parser after the upload
|
|
163
164
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
164
|
-
program_id="p_…", #
|
|
165
|
+
program_id="p_…", # the program the deployment belongs to; serve requires it after self-host 2026-001
|
|
165
166
|
)
|
|
166
167
|
```
|
|
167
168
|
|
|
@@ -111,7 +111,7 @@ cmpnd.deploy(
|
|
|
111
111
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
112
112
|
timeout=300, # optional: seconds to wait for the parser after the upload
|
|
113
113
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
114
|
-
program_id="p_…", #
|
|
114
|
+
program_id="p_…", # the program the deployment belongs to; serve requires it after self-host 2026-001
|
|
115
115
|
)
|
|
116
116
|
```
|
|
117
117
|
|
|
@@ -83,8 +83,7 @@ def _parse_iso(ts: str | None) -> datetime | None:
|
|
|
83
83
|
if not ts:
|
|
84
84
|
return None
|
|
85
85
|
try:
|
|
86
|
-
|
|
87
|
-
return datetime.fromisoformat(ts.replace("Z", "+00:00"))
|
|
86
|
+
return datetime.fromisoformat(ts)
|
|
88
87
|
except (ValueError, TypeError):
|
|
89
88
|
return None
|
|
90
89
|
|
|
@@ -811,11 +810,12 @@ def _parse_deploy_metadata(raw: str | None) -> dict[str, Any] | None:
|
|
|
811
810
|
raise api_client.CliError(f"--metadata is invalid: {exc}")
|
|
812
811
|
|
|
813
812
|
|
|
814
|
-
def _program_id_arg(value: str | None
|
|
813
|
+
def _program_id_arg(value: str | None) -> str | None:
|
|
815
814
|
"""The program id a deploy or optimize names: ``--program-id``, else ``CMPND_PROGRAM_ID``.
|
|
816
815
|
|
|
817
|
-
Checked here, before a file is staged, so a
|
|
818
|
-
|
|
816
|
+
Checked here, before a file is staged, so a mistyped id is a usage error naming
|
|
817
|
+
its source rather than a refusal after work was done. serve decides whether a
|
|
818
|
+
deployment needs an id, so a missing one is not refused here.
|
|
819
819
|
"""
|
|
820
820
|
from ... import identity
|
|
821
821
|
|
|
@@ -823,12 +823,6 @@ def _program_id_arg(value: str | None, *, required: bool) -> str | None:
|
|
|
823
823
|
if value is None and os.environ.get("CMPND_PROGRAM_ID"):
|
|
824
824
|
value, source = os.environ["CMPND_PROGRAM_ID"], "CMPND_PROGRAM_ID"
|
|
825
825
|
if value is None:
|
|
826
|
-
if required:
|
|
827
|
-
raise api_client.CliError(
|
|
828
|
-
"--program-id is required: a deployment always names its program. "
|
|
829
|
-
"Create one with `cmpnd programs create`, then pass --program-id p_… "
|
|
830
|
-
"(or set CMPND_PROGRAM_ID)."
|
|
831
|
-
)
|
|
832
826
|
return None
|
|
833
827
|
try:
|
|
834
828
|
return identity.validate_program_id(value, source=source)
|
|
@@ -855,9 +849,7 @@ def cmd_deploy(client: api_client.ApiClient, args: Any) -> None:
|
|
|
855
849
|
|
|
856
850
|
from ... import authored, configuration, deployment
|
|
857
851
|
|
|
858
|
-
|
|
859
|
-
# names its program, and the server would refuse the create anyway.
|
|
860
|
-
program_id = _program_id_arg(getattr(args, "program_id", None), required=True)
|
|
852
|
+
program_id = _program_id_arg(getattr(args, "program_id", None))
|
|
861
853
|
configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=program_id)
|
|
862
854
|
try:
|
|
863
855
|
if args.source == "-" or args.source is None:
|
|
@@ -881,7 +873,10 @@ def cmd_deploy(client: api_client.ApiClient, args: Any) -> None:
|
|
|
881
873
|
|
|
882
874
|
metadata = _parse_deploy_metadata(getattr(args, "metadata", None))
|
|
883
875
|
print(_c("deploying…", "dim"), file=sys.stderr)
|
|
884
|
-
|
|
876
|
+
try:
|
|
877
|
+
deployed = deployment.deploy_bundle(prepared.bundle, prepared.facts, metadata=metadata, program_id=program_id)
|
|
878
|
+
except ValueError as exc:
|
|
879
|
+
raise api_client.CliError(str(exc)) from exc
|
|
885
880
|
|
|
886
881
|
deployment_id = deployed.deployment_id
|
|
887
882
|
print(deployment_id)
|
|
@@ -946,9 +941,7 @@ def cmd_optimize(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
946
941
|
from ... import authored, configuration, optimization
|
|
947
942
|
|
|
948
943
|
deployment_id = getattr(args, "deployment_id", None)
|
|
949
|
-
|
|
950
|
-
# already names its program.
|
|
951
|
-
program_id = _program_id_arg(getattr(args, "program_id", None), required=deployment_id is None)
|
|
944
|
+
program_id = _program_id_arg(getattr(args, "program_id", None))
|
|
952
945
|
configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=program_id)
|
|
953
946
|
try:
|
|
954
947
|
if args.source == "-" or args.source is None:
|
|
@@ -1266,7 +1259,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1266
1259
|
dest="program_id",
|
|
1267
1260
|
default=None,
|
|
1268
1261
|
help="Program id (p_…) the deployment belongs to, from `cmpnd programs create`. "
|
|
1269
|
-
"Required
|
|
1262
|
+
"Defaults to CMPND_PROGRAM_ID. Required by every serve after self-host release 2026-001",
|
|
1270
1263
|
)
|
|
1271
1264
|
dp.add_argument(
|
|
1272
1265
|
"--entrypoint",
|
|
@@ -1351,8 +1344,8 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1351
1344
|
dest="program_id",
|
|
1352
1345
|
default=None,
|
|
1353
1346
|
help="Program id (p_…) being optimized, from `cmpnd programs create`; defaults to "
|
|
1354
|
-
"CMPND_PROGRAM_ID. Required
|
|
1355
|
-
"with --deployment-id",
|
|
1347
|
+
"CMPND_PROGRAM_ID. Required by every serve after self-host release 2026-001 when "
|
|
1348
|
+
"the file's program is deployed here, optional with --deployment-id",
|
|
1356
1349
|
)
|
|
1357
1350
|
opt.add_argument(
|
|
1358
1351
|
"--reflection-model",
|
|
@@ -490,8 +490,8 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
|
|
|
490
490
|
"""Deploy authored Python from a file or ``"-"`` for stdin.
|
|
491
491
|
|
|
492
492
|
``program_id`` (``p_…``, from ``cmpnd programs create``) names the program
|
|
493
|
-
the deployment belongs to; it defaults to ``CMPND_PROGRAM_ID
|
|
494
|
-
|
|
493
|
+
the deployment belongs to; it defaults to ``CMPND_PROGRAM_ID``. serve
|
|
494
|
+
decides whether a deployment needs one. A fresh child imports the staged bundle. The shell
|
|
495
495
|
does not execute the file in its own process. Returns the
|
|
496
496
|
new Deployment entity so you can chain ``.watch()`` / ``.run({...})``
|
|
497
497
|
directly; also invalidates ``deps`` so the new deployment shows up
|
|
@@ -499,7 +499,7 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
|
|
|
499
499
|
"""
|
|
500
500
|
from .. import authored, configuration, deployment
|
|
501
501
|
|
|
502
|
-
declared = commands.top._program_id_arg(program_id
|
|
502
|
+
declared = commands.top._program_id_arg(program_id)
|
|
503
503
|
configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=declared)
|
|
504
504
|
if source in ("-", None):
|
|
505
505
|
prepared = authored.prepare_stdin(
|
|
@@ -644,7 +644,7 @@ def _enable_readline(namespace: dict[str, Any]) -> None:
|
|
|
644
644
|
def _launch_repl(namespace: dict[str, Any], banner: str) -> None:
|
|
645
645
|
"""Prefer IPython (Jedi completion, history, multi-line); fall back to stdlib."""
|
|
646
646
|
try:
|
|
647
|
-
from IPython import start_ipython
|
|
647
|
+
from IPython import start_ipython
|
|
648
648
|
from traitlets.config import Config
|
|
649
649
|
except ImportError:
|
|
650
650
|
import code
|
|
@@ -194,8 +194,8 @@ _TS_RE = re.compile(r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(\.\d+)?(Z|[+-]\d{2}
|
|
|
194
194
|
|
|
195
195
|
def _parse_ts(value: Any) -> datetime.datetime | None:
|
|
196
196
|
"""Parse an RFC3339 timestamp tolerantly. Server emits nanosecond (9-digit)
|
|
197
|
-
fractions
|
|
198
|
-
|
|
197
|
+
fractions, so truncate the fraction to microseconds, the precision datetime
|
|
198
|
+
holds, and normalize a trailing Z. Returns None on anything unparsable
|
|
199
199
|
— the caller degrades (offset 0) rather than crashing."""
|
|
200
200
|
if not isinstance(value, str):
|
|
201
201
|
return None
|
|
@@ -346,21 +346,35 @@ def _resolve_mcp_tool_references(client: httpx.Client, config, references: list[
|
|
|
346
346
|
|
|
347
347
|
|
|
348
348
|
MISSING_PROGRAM_ID = (
|
|
349
|
-
"
|
|
349
|
+
"this server requires a program id: pass program_id= (`cmpnd deploy --program-id`), or set "
|
|
350
350
|
"cmpnd.configure(program_id=...) or CMPND_PROGRAM_ID. Create one with `cmpnd programs create`."
|
|
351
351
|
)
|
|
352
352
|
|
|
353
|
+
# The error serve answers, with a 400, to a create that names no program. A serve
|
|
354
|
+
# from before program ids accepts the create instead. serve pins this prefix in
|
|
355
|
+
# deploymentsapi.missingProgramIDError.
|
|
356
|
+
_SERVE_MISSING_PROGRAM_ID = "program_id is required"
|
|
353
357
|
|
|
354
|
-
|
|
358
|
+
|
|
359
|
+
def declared_program_id(explicit: str | None, config: configuration.Config) -> str | None:
|
|
355
360
|
"""The program a deployment is created under: the explicit id, else the configured one.
|
|
356
361
|
|
|
357
|
-
A
|
|
358
|
-
|
|
362
|
+
A declared id is checked for shape before anything is packaged or sent. serve
|
|
363
|
+
decides whether a deployment needs an id, so a missing one is not refused here.
|
|
359
364
|
"""
|
|
360
365
|
chosen = explicit if explicit is not None else config.program_id
|
|
361
|
-
if chosen is None
|
|
362
|
-
|
|
363
|
-
|
|
366
|
+
return identity.validate_program_id(chosen) if chosen is not None else None
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _refused_for_missing_program_id(response: httpx.Response, deploy_body: dict[str, Any]) -> bool:
|
|
370
|
+
"""Whether serve refused a create that named no program because it needs one."""
|
|
371
|
+
if response.status_code != 400 or "program_id" in deploy_body:
|
|
372
|
+
return False
|
|
373
|
+
try:
|
|
374
|
+
error = response.json().get("error")
|
|
375
|
+
except (ValueError, AttributeError):
|
|
376
|
+
return False
|
|
377
|
+
return isinstance(error, str) and error.startswith(_SERVE_MISSING_PROGRAM_ID)
|
|
364
378
|
|
|
365
379
|
|
|
366
380
|
def deploy(module, metric=None, timeout=300, metadata=None, *, program_id=None):
|
|
@@ -387,22 +401,24 @@ def deploy(module, metric=None, timeout=300, metadata=None, *, program_id=None):
|
|
|
387
401
|
with string keys, within 64 KiB. Read it back via the deployment
|
|
388
402
|
record (``cmpnd.status`` / the deployment GET API).
|
|
389
403
|
program_id: The program (``p_…``) the deployment belongs to, as
|
|
390
|
-
``cmpnd programs create`` printed it.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
404
|
+
``cmpnd programs create`` printed it. When omitted, the configured
|
|
405
|
+
id (``cmpnd.configure(program_id=...)`` or ``CMPND_PROGRAM_ID``) is
|
|
406
|
+
used. With neither, the create names no program, and serve decides:
|
|
407
|
+
every serve with program ids refuses it, and a serve from before
|
|
408
|
+
them, such as self-host release 2026-001, accepts it.
|
|
394
409
|
|
|
395
410
|
Returns:
|
|
396
411
|
A DeployedProgram that can be called with the same inputs as the
|
|
397
412
|
original module. Has a .deployment_id attribute and str() returns it.
|
|
398
413
|
|
|
399
414
|
Raises:
|
|
400
|
-
ValueError: If
|
|
415
|
+
ValueError: If the program id is malformed, or if serve requires one and
|
|
416
|
+
none was given or configured.
|
|
401
417
|
RuntimeError: If cmpnd is not configured, or if deployment fails.
|
|
402
418
|
TimeoutError: If the program isn't ready within timeout seconds.
|
|
403
419
|
"""
|
|
404
420
|
config = configuration.require_config()
|
|
405
|
-
|
|
421
|
+
program = declared_program_id(program_id, config)
|
|
406
422
|
|
|
407
423
|
# Resolve the program's MCP tool references against the org's registry, before
|
|
408
424
|
# anything is packaged and before a deployment row exists. A program with no MCP
|
|
@@ -423,12 +439,15 @@ def deploy(module, metric=None, timeout=300, metadata=None, *, program_id=None):
|
|
|
423
439
|
program_signature_hash = identity.compute_program_hash(module) or 0
|
|
424
440
|
|
|
425
441
|
deploy_body: dict[str, Any] = {
|
|
426
|
-
"program_id": declared_program_id,
|
|
427
442
|
"program_signature_hash": identity.format_signature_hash(program_signature_hash),
|
|
428
443
|
# Declare the ZIP's exact length so the server can size-bound the upload
|
|
429
444
|
# slot and reject an oversized deploy before signing it (Slice E).
|
|
430
445
|
"declared_content_length": len(zip_bytes),
|
|
431
446
|
}
|
|
447
|
+
# Left off when undeclared, so a serve from before program ids reads the body it
|
|
448
|
+
# always read and a newer serve answers with its own refusal.
|
|
449
|
+
if program is not None:
|
|
450
|
+
deploy_body["program_id"] = program
|
|
432
451
|
# Carry the caller's metadata blob (validated and made jsonb-storable at the
|
|
433
452
|
# call site) as a reserved top-level body key, committed with the deployment
|
|
434
453
|
# record server-side.
|
|
@@ -496,13 +515,14 @@ def deploy_bundle(
|
|
|
496
515
|
) -> execution.DeployedProgram:
|
|
497
516
|
"""Upload a checked authored-source bundle without packaging a live module.
|
|
498
517
|
|
|
499
|
-
``program_id``
|
|
500
|
-
|
|
518
|
+
``program_id`` works as it does for :func:`deploy`: the explicit id, else the
|
|
519
|
+
configured one, else none, and serve decides whether a deployment needs one.
|
|
501
520
|
"""
|
|
502
521
|
config = configuration.require_config()
|
|
503
|
-
|
|
522
|
+
program = declared_program_id(program_id, config)
|
|
504
523
|
deploy_body = facts.deploy_body()
|
|
505
|
-
|
|
524
|
+
if program is not None:
|
|
525
|
+
deploy_body["program_id"] = program
|
|
506
526
|
deploy_body["source_format"] = "authored"
|
|
507
527
|
deploy_body["declared_content_length"] = len(zip_bytes)
|
|
508
528
|
if metadata is not None:
|
|
@@ -531,6 +551,8 @@ def _deploy_prepared(
|
|
|
531
551
|
may_resend_with_no_answer=retry.never_left_the_client,
|
|
532
552
|
may_resend_after_answer=lambda _: False,
|
|
533
553
|
)
|
|
554
|
+
if _refused_for_missing_program_id(created, deploy_body):
|
|
555
|
+
raise ValueError(MISSING_PROGRAM_ID)
|
|
534
556
|
_raise_http_error(created, "create deployment")
|
|
535
557
|
answer = created.json()
|
|
536
558
|
deployment_id = answer["deployment_id"]
|
|
@@ -38,7 +38,7 @@ from typing import TYPE_CHECKING, Any, Callable, cast
|
|
|
38
38
|
import httpx
|
|
39
39
|
from httpx import HTTPError
|
|
40
40
|
|
|
41
|
-
from . import _deployments, _http, authored, configuration, deployment, execution,
|
|
41
|
+
from . import _deployments, _http, authored, configuration, deployment, execution, packaging, retry
|
|
42
42
|
from .deployment_metadata import DeploymentMetadataError, DeploymentSignatureResponse
|
|
43
43
|
|
|
44
44
|
if TYPE_CHECKING:
|
|
@@ -831,10 +831,11 @@ def optimize(
|
|
|
831
831
|
deployment_id: Skip the initial deploy by reusing an existing ready
|
|
832
832
|
deployment as program A.
|
|
833
833
|
program_id: The program (``p_…``) being optimized. Defaults to the
|
|
834
|
-
configured id.
|
|
835
|
-
``deployment_id``),
|
|
836
|
-
|
|
837
|
-
the first optimize step, the one that optimizes your
|
|
834
|
+
configured id. When the program is deployed here (no
|
|
835
|
+
``deployment_id``), the deploy carries it, and serve decides whether
|
|
836
|
+
that deploy needs one. A reused deployment already names its program.
|
|
837
|
+
Sent on the first optimize step, the one that optimizes your
|
|
838
|
+
deployment.
|
|
838
839
|
reflection_lm: **Required** — the model that proposes new instructions.
|
|
839
840
|
The search is only as good as it is, so this is a strong model,
|
|
840
841
|
typically not the one being optimized. Pass the ``dspy.LM`` you would
|
|
@@ -925,7 +926,7 @@ def optimize(
|
|
|
925
926
|
_apply_budget(config, max_metric_calls=max_metric_calls, auto=auto)
|
|
926
927
|
|
|
927
928
|
cfg = configuration.require_config()
|
|
928
|
-
program_id =
|
|
929
|
+
program_id = deployment.declared_program_id(program_id, cfg)
|
|
929
930
|
|
|
930
931
|
from . import lm_configuration
|
|
931
932
|
|
|
@@ -957,19 +958,6 @@ def optimize(
|
|
|
957
958
|
return _deployed_program(best_deployment_id, cfg, score=best_score)
|
|
958
959
|
|
|
959
960
|
|
|
960
|
-
def _declared_program_id(explicit: str | None, cfg: configuration.Config, *, deploys: bool) -> str | None:
|
|
961
|
-
"""The program an optimization names: the explicit id, else the configured one.
|
|
962
|
-
|
|
963
|
-
Required when this call deploys the program, since a deployment always names its
|
|
964
|
-
program, and refused before anything is sent. Optional when an existing
|
|
965
|
-
deployment is reused, because that deployment already names one.
|
|
966
|
-
"""
|
|
967
|
-
if deploys:
|
|
968
|
-
return deployment.require_program_id(explicit, cfg)
|
|
969
|
-
chosen = explicit if explicit is not None else cfg.program_id
|
|
970
|
-
return identity.validate_program_id(chosen) if chosen is not None else None
|
|
971
|
-
|
|
972
|
-
|
|
973
961
|
def _run_steps(
|
|
974
962
|
cfg: configuration.Config,
|
|
975
963
|
bundle: bytes,
|
|
@@ -1094,8 +1082,8 @@ def optimize_authored(
|
|
|
1094
1082
|
one directory on the executor, so a path they disagree about is refused, and it is
|
|
1095
1083
|
worth refusing here where both files are in reach.
|
|
1096
1084
|
|
|
1097
|
-
``program_id`` is :func:`optimize`'s:
|
|
1098
|
-
|
|
1085
|
+
``program_id`` is :func:`optimize`'s: the deploy of the file's program carries it,
|
|
1086
|
+
and serve decides whether that deploy needs one.
|
|
1099
1087
|
"""
|
|
1100
1088
|
check_optimizer(optimizer)
|
|
1101
1089
|
config = dict(config or {})
|
|
@@ -1111,7 +1099,7 @@ def optimize_authored(
|
|
|
1111
1099
|
_apply_budget(config, max_metric_calls=max_metric_calls, auto=auto)
|
|
1112
1100
|
|
|
1113
1101
|
cfg = configuration.require_config()
|
|
1114
|
-
program_id =
|
|
1102
|
+
program_id = deployment.declared_program_id(program_id, cfg)
|
|
1115
1103
|
|
|
1116
1104
|
facts = prepared.facts.program
|
|
1117
1105
|
if prepared.program_bundle is not None:
|
|
@@ -460,8 +460,8 @@ def _collect_inlined_base_imports(
|
|
|
460
460
|
if typing_extensions.is_typeddict(ann_type):
|
|
461
461
|
# A TypedDict subclass reports `dict` as its base — the name its source
|
|
462
462
|
# actually spells survives only in the text. Use typing_extensions for
|
|
463
|
-
# the bare spelling because Pydantic requires it on Python 3.
|
|
464
|
-
#
|
|
463
|
+
# the bare spelling because Pydantic requires it on Python 3.11.
|
|
464
|
+
# Import both modules to cover either qualified spelling.
|
|
465
465
|
imports.add(ImportEntry("typing_extensions", "TypedDict"))
|
|
466
466
|
imports.add(ImportEntry("typing_extensions"))
|
|
467
467
|
imports.add(ImportEntry("typing"))
|
|
@@ -19,6 +19,11 @@ from . import _http, configuration
|
|
|
19
19
|
|
|
20
20
|
DEFAULT_ENDPOINT = "https://platform.cmpnd.ai"
|
|
21
21
|
|
|
22
|
+
# Self-host release 2026-001 answers a programs create with 405, because it routes
|
|
23
|
+
# GET requests under /api/v1/programs/ and has no create. Every newer serve accepts
|
|
24
|
+
# the create, so on this one route a 405 means a serve from before program ids.
|
|
25
|
+
UNSUPPORTED_STATUS = 405
|
|
26
|
+
|
|
22
27
|
|
|
23
28
|
def create(
|
|
24
29
|
name: str | None = None,
|
|
@@ -61,7 +66,18 @@ def send_create(
|
|
|
61
66
|
body["name"] = name
|
|
62
67
|
if optimized_from_run_id is not None:
|
|
63
68
|
body["optimized_from_run_id"] = optimized_from_run_id
|
|
64
|
-
|
|
69
|
+
try:
|
|
70
|
+
return client.post("/api/v1/programs", json=body)
|
|
71
|
+
except _http.ApiError as exc:
|
|
72
|
+
if exc.status_code == UNSUPPORTED_STATUS:
|
|
73
|
+
raise _http.ApiError(
|
|
74
|
+
"This server does not support program ids. A serve from before program ids, such as "
|
|
75
|
+
"self-host release 2026-001, deploys without one: run `cmpnd deploy` without "
|
|
76
|
+
f"--program-id.\n {exc}",
|
|
77
|
+
exc.exit_code,
|
|
78
|
+
status_code=exc.status_code,
|
|
79
|
+
) from exc
|
|
80
|
+
raise
|
|
65
81
|
|
|
66
82
|
|
|
67
83
|
def _client(api_key: str | None, endpoint: str | None) -> _http.ApiClient:
|
|
@@ -19,10 +19,15 @@ PROGRAM_ID=$(cmpnd programs create --name triage)
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
The command reports what it created on stderr, and `--json` prints the whole
|
|
22
|
-
registry row instead. `cmpnd deploy`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
registry row instead. `cmpnd deploy` takes the id as `--program-id`, and so
|
|
23
|
+
does `cmpnd optimize` when it deploys the file's program first. With
|
|
24
|
+
`--deployment-id`, the id is optional because that deployment already names its
|
|
25
|
+
program. The CLI checks a given id's shape and leaves the requirement to serve.
|
|
26
|
+
Every serve after self-host release 2026-001 refuses a deploy with no id, and
|
|
27
|
+
the CLI then names `--program-id` and `cmpnd programs create`. Self-host release
|
|
28
|
+
2026-001 has no program ids, so a deploy there omits `--program-id`, and
|
|
29
|
+
`cmpnd programs create` reports that the server does not support them. Each
|
|
30
|
+
call creates a new program. The command never
|
|
26
31
|
retries, because a second send would create a second program.
|
|
27
32
|
`cmpnd.programs.create(name=...)` makes the same call from Python and returns
|
|
28
33
|
the row.
|
|
@@ -444,7 +444,7 @@ base written inside a function belongs to no module's globals, so a bare name
|
|
|
444
444
|
falls back to the runtime base at that position. A `TypedDict` subclass is the
|
|
445
445
|
one base read off the class rather than the text, because it reports `dict`:
|
|
446
446
|
`typing_extensions` supplies the name, which is what pydantic requires on Python
|
|
447
|
-
3.
|
|
447
|
+
3.11.
|
|
448
448
|
|
|
449
449
|
Two shapes refuse the package rather than deploying a program that raises
|
|
450
450
|
`NameError` on its first call, which is well after deploy reported it ready:
|
|
@@ -757,11 +757,14 @@ the key is left off the wire rather than sent as `null`, so an undeclared trace
|
|
|
757
757
|
it did before ids existed. The finalize body carries no id, because it restates no
|
|
758
758
|
creation field.
|
|
759
759
|
|
|
760
|
-
|
|
761
|
-
`
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
760
|
+
`deploy()` and `deploy_bundle()` take `program_id=` and fall back to the configured id
|
|
761
|
+
(`deployment.declared_program_id`). A given id is checked for shape before anything is
|
|
762
|
+
packaged or sent. With no id the create body leaves the key off, and serve decides.
|
|
763
|
+
Every serve after self-host release 2026-001 refuses that create with a `400`, which the
|
|
764
|
+
SDK raises as `ValueError` naming `cmpnd programs create`. Self-host release 2026-001
|
|
765
|
+
has no program ids and accepts it. `optimize()` and `optimize_authored()` pass the id to
|
|
766
|
+
the deploy when they deploy the program themselves. A reused `deployment_id` already
|
|
767
|
+
names its program, so the id is optional there. Later steps
|
|
765
768
|
optimize a result deployment the platform created and whose program it allocated, so
|
|
766
769
|
the caller's id rides only the steps on the caller's own deployment.
|
|
767
770
|
|
|
@@ -11,7 +11,7 @@ description = "The cmpnd ingest transport: the HTTP client that pushes traces, o
|
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
# `cmpnd`'s floor: these modules ship inside its wheel, so they must import on
|
|
13
13
|
# every Python it supports.
|
|
14
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.11"
|
|
15
15
|
license = {text = "MIT"}
|
|
16
16
|
authors = [
|
|
17
17
|
{name = "cmpnd", email = "hello@cmpnd.ai"}
|
|
@@ -5,10 +5,10 @@ name = "cmpnd"
|
|
|
5
5
|
# it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
|
|
6
6
|
# hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
|
|
7
7
|
# this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.42.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
12
|
license = {text = "MIT"}
|
|
13
13
|
authors = [
|
|
14
14
|
{name = "cmpnd", email = "hello@cmpnd.ai"}
|
|
@@ -19,11 +19,11 @@ classifiers = [
|
|
|
19
19
|
"Intended Audience :: Developers",
|
|
20
20
|
"License :: OSI Approved :: MIT License",
|
|
21
21
|
"Programming Language :: Python :: 3",
|
|
22
|
-
"Programming Language :: Python :: 3.10",
|
|
23
22
|
"Programming Language :: Python :: 3.11",
|
|
24
23
|
"Programming Language :: Python :: 3.12",
|
|
25
24
|
"Programming Language :: Python :: 3.13",
|
|
26
25
|
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Programming Language :: Python :: 3.15",
|
|
27
27
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
28
|
]
|
|
29
29
|
|
|
@@ -46,7 +46,7 @@ dependencies = [
|
|
|
46
46
|
"pydantic>=2.0",
|
|
47
47
|
# Detects TypedDicts from both typing and typing_extensions, and supplies
|
|
48
48
|
# the spelling Pydantic requires when generated programs run on Python
|
|
49
|
-
# 3.
|
|
49
|
+
# 3.11.
|
|
50
50
|
"typing-extensions>=4.1.0",
|
|
51
51
|
# Still required, and still the fast path — but `cmpnd/ir/xxh64.py` no
|
|
52
52
|
# longer *needs* it: it falls back to a pure-Python xxh64 that the tests
|
|
@@ -56,9 +56,8 @@ dependencies = [
|
|
|
56
56
|
# install should have it.
|
|
57
57
|
"xxhash>=3.0.0",
|
|
58
58
|
# Powers the interactive `cmpnd` shell (Jedi completion, multi-line,
|
|
59
|
-
# history search, syntax highlighting). No upper cap
|
|
60
|
-
#
|
|
61
|
-
# `code.interact` + rlcompleter if IPython somehow can't import.
|
|
59
|
+
# history search, syntax highlighting). No upper cap. The shell falls back
|
|
60
|
+
# to stdlib `code.interact` + rlcompleter if IPython somehow can't import.
|
|
62
61
|
"ipython>=8.20",
|
|
63
62
|
]
|
|
64
63
|
|
|
@@ -95,16 +94,20 @@ dev = [
|
|
|
95
94
|
"ruff>=0.4.0",
|
|
96
95
|
"basedpyright>=1.39",
|
|
97
96
|
"jsonschema>=4.0",
|
|
97
|
+
# The tests import litellm (tests/e2e/fake_lm.py and the modules that reuse it) and
|
|
98
|
+
# gepa directly. dspy 3.4.1 installs both only below Python 3.15, because both declare
|
|
99
|
+
# requires-python <3.15. uv ignores that upper bound, so the 3.15 test leg still
|
|
100
|
+
# installs them.
|
|
101
|
+
"litellm",
|
|
102
|
+
"gepa",
|
|
98
103
|
# litellm's bedrock/ provider imports boto3 in-process, so the client-side
|
|
99
104
|
# Bedrock stress tests (committee twins) need it in the test env.
|
|
100
105
|
"boto3>=1.34",
|
|
101
106
|
# test_reflector_smoke.py builds numpy fixtures. dspy <=3.2.x required numpy
|
|
102
107
|
# unconditionally so it rode in transitively; dspy 3.3.0 moved numpy behind a
|
|
103
108
|
# `numpy` extra, so declare it directly as the test dependency it always was.
|
|
104
|
-
# numpy 2.3
|
|
105
|
-
|
|
106
|
-
"numpy>=1.26; python_version < '3.11'",
|
|
107
|
-
"numpy>=2.3; python_version >= '3.11'",
|
|
109
|
+
# numpy 2.3 is the first release with cp314 wheels.
|
|
110
|
+
"numpy>=2.3",
|
|
108
111
|
# tests/e2e/test_deploy_pandas.py deploys a program and a metric that import pandas,
|
|
109
112
|
# because the worker's kernel ships it. The SDK reads a function's imports from the
|
|
110
113
|
# live module before packaging it, so pandas has to be importable on the client.
|
|
@@ -124,12 +127,8 @@ dev = [
|
|
|
124
127
|
# integration stack points programs at. Carried as an SDK extra so a single
|
|
125
128
|
# `uv run --project python-sdk --extra fake-provider` brings up the SDK and the
|
|
126
129
|
# provider together — no separate venv to forget about.
|
|
127
|
-
#
|
|
128
|
-
# It targets python >=3.11, so the marker is gated: without it, resolution for
|
|
129
|
-
# the (3.10-supporting) SDK fails. The extra is dev-only and we always run it on
|
|
130
|
-
# 3.11+ (bin/setup uses 3.11).
|
|
131
130
|
fake-provider = [
|
|
132
|
-
"cmpnd-fake-provider
|
|
131
|
+
"cmpnd-fake-provider",
|
|
133
132
|
]
|
|
134
133
|
|
|
135
134
|
[tool.uv.sources]
|
|
@@ -224,7 +223,7 @@ markers = [
|
|
|
224
223
|
|
|
225
224
|
[tool.ruff]
|
|
226
225
|
line-length = 120
|
|
227
|
-
target-version = "
|
|
226
|
+
target-version = "py311"
|
|
228
227
|
|
|
229
228
|
[tool.ruff.lint]
|
|
230
229
|
select = ["E", "F", "I", "W"]
|
|
@@ -256,7 +255,7 @@ select = ["E", "F", "I", "W"]
|
|
|
256
255
|
# no relaxations, so it gets no executionEnvironment of its own.
|
|
257
256
|
include = ["cmpnd", "ingest/cmpnd_ingest", "examples", "tests/stress", "tests/e2e", "tests/load"]
|
|
258
257
|
stubPath = "stubs"
|
|
259
|
-
pythonVersion = "3.
|
|
258
|
+
pythonVersion = "3.11"
|
|
260
259
|
reportAny = false
|
|
261
260
|
reportExplicitAny = false
|
|
262
261
|
reportUnknownMemberType = false
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install cmpnd with pip's own resolver and check that the installed package
|
|
3
|
+
# imports and instruments DSPy. Called by .github/workflows/ci-sdk.yml (the
|
|
4
|
+
# sdk-test leg for Python 3.15).
|
|
5
|
+
#
|
|
6
|
+
# `pip install cmpnd` is the install PyPI advertises. pip honours the
|
|
7
|
+
# requires-python upper bounds that uv ignores, so this check fails when no
|
|
8
|
+
# dspy release admits the Python version. PYO3_USE_ABI3_FORWARD_COMPATIBILITY
|
|
9
|
+
# is set to 0, so an extension without a wheel for this Python fails the
|
|
10
|
+
# install and does not build from source.
|
|
11
|
+
#
|
|
12
|
+
# Usage: scripts/check-pip-install.sh <python-version> <dspy-version>
|
|
13
|
+
# e.g. scripts/check-pip-install.sh 3.15 3.4.1
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
if [ "$#" -ne 2 ]; then
|
|
17
|
+
echo "usage: $0 <python-version> <dspy-version>" >&2
|
|
18
|
+
exit 2
|
|
19
|
+
fi
|
|
20
|
+
python_version=$1
|
|
21
|
+
dspy_version=$2
|
|
22
|
+
|
|
23
|
+
sdk_dir=$(cd "$(dirname "$0")/.." && pwd)
|
|
24
|
+
venv_dir=$(mktemp -d)
|
|
25
|
+
trap 'rm -rf "$venv_dir"' EXIT
|
|
26
|
+
|
|
27
|
+
uv venv --seed --python "$python_version" "$venv_dir"
|
|
28
|
+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=0 \
|
|
29
|
+
"$venv_dir/bin/python" -m pip install "$sdk_dir" "dspy==$dspy_version"
|
|
30
|
+
|
|
31
|
+
# -I keeps the checkout off sys.path, so the import reads the installed
|
|
32
|
+
# package and not the source tree.
|
|
33
|
+
cd "$venv_dir"
|
|
34
|
+
"$venv_dir/bin/python" -I -c "import cmpnd; cmpnd.configure(api_key='ci'); cmpnd.auto_instrument(); print('cmpnd', cmpnd.__file__)"
|