cmpnd 0.80.0__tar.gz → 0.81.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.80.0 → cmpnd-0.81.0}/PKG-INFO +4 -1
- {cmpnd-0.80.0 → cmpnd-0.81.0}/README.md +3 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/__init__.py +2 -1
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/client.py +3 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment_runs.py +70 -22
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/execution.py +3 -1
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/sdk-instrumentation.md +14 -2
- {cmpnd-0.80.0 → cmpnd-0.81.0}/pyproject.toml +1 -1
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployment_runs.py +89 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_execute.py +31 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/uv.lock +1 -1
- {cmpnd-0.80.0 → cmpnd-0.81.0}/.gitignore +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/AGENTS.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/CLAUDE.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/context.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/program_naming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/cli.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/client.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/README.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/drain.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_context.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_program_id.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_integration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_no_signature_hash_on_the_wire.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_phase_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_naming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.81.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.81.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>
|
|
@@ -722,6 +722,9 @@ errors:
|
|
|
722
722
|
|
|
723
723
|
- A refused request raises `httpx.HTTPStatusError`.
|
|
724
724
|
- A lost or failed submission reply raises `RunSubmissionUncertain`.
|
|
725
|
+
- A connection to the platform that never opened, such as one refused, raises
|
|
726
|
+
`RunNotSubmitted` after a few attempts. It names the endpoint, and nothing was
|
|
727
|
+
sent, so submitting again is safe. It is a `RunSubmissionUncertain`.
|
|
725
728
|
- A spent budget raises `RunWaitTimeout`, which holds the run ID.
|
|
726
729
|
- An answer that expired before it was read raises `RunResultExpired`.
|
|
727
730
|
|
|
@@ -671,6 +671,9 @@ errors:
|
|
|
671
671
|
|
|
672
672
|
- A refused request raises `httpx.HTTPStatusError`.
|
|
673
673
|
- A lost or failed submission reply raises `RunSubmissionUncertain`.
|
|
674
|
+
- A connection to the platform that never opened, such as one refused, raises
|
|
675
|
+
`RunNotSubmitted` after a few attempts. It names the endpoint, and nothing was
|
|
676
|
+
sent, so submitting again is safe. It is a `RunSubmissionUncertain`.
|
|
674
677
|
- A spent budget raises `RunWaitTimeout`, which holds the run ID.
|
|
675
678
|
- An answer that expired before it was read raises `RunResultExpired`.
|
|
676
679
|
|
|
@@ -37,7 +37,7 @@ from .deployment_metadata import (
|
|
|
37
37
|
DeploymentSignatureResponse,
|
|
38
38
|
UnsupportedDeploymentMetadataVersion,
|
|
39
39
|
)
|
|
40
|
-
from .deployment_runs import RunResultExpired, RunSubmissionUncertain, RunWaitTimeout
|
|
40
|
+
from .deployment_runs import RunNotSubmitted, RunResultExpired, RunSubmissionUncertain, RunWaitTimeout
|
|
41
41
|
from .execution import DeployedProgram, RetryableProviderError
|
|
42
42
|
from .exporter import flush_exporter, shutdown_exporter
|
|
43
43
|
from .lm_configuration import HostedLM, SystemOne, configure_lm
|
|
@@ -120,6 +120,7 @@ __all__ = [
|
|
|
120
120
|
"DeploymentMetadataError",
|
|
121
121
|
"UnsupportedDeploymentMetadataVersion",
|
|
122
122
|
"RunSubmissionUncertain",
|
|
123
|
+
"RunNotSubmitted",
|
|
123
124
|
"RunWaitTimeout",
|
|
124
125
|
"RunResultExpired",
|
|
125
126
|
"DeployedProgram",
|
|
@@ -360,6 +360,9 @@ class Client:
|
|
|
360
360
|
failure. No run is started again automatically.
|
|
361
361
|
RunSubmissionUncertain: If the POST reply was lost or was a server
|
|
362
362
|
error, so serve may have accepted the run.
|
|
363
|
+
RunNotSubmitted: If no connection to serve opened, after a few
|
|
364
|
+
attempts inside the budget. Nothing was sent. It is a
|
|
365
|
+
``RunSubmissionUncertain``.
|
|
363
366
|
RunWaitTimeout: If the run has not settled within the local budget.
|
|
364
367
|
The run continues.
|
|
365
368
|
RunResultExpired: If the retained answer expired before it was read.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""Durable deployment run submission, discovery, and result retrieval.
|
|
2
2
|
|
|
3
|
-
Submission sends one POST and never repeats it. A lost or
|
|
4
|
-
an accepted run, so callers inspect the run list before
|
|
5
|
-
submit new work.
|
|
6
|
-
|
|
3
|
+
Submission sends one POST and never repeats it once a connection opened. A lost or
|
|
4
|
+
failed reply may hide an accepted run, so callers inspect the run list before
|
|
5
|
+
deciding whether to submit new work. A connection that never opened sent nothing,
|
|
6
|
+
so the POST is tried again a few times inside the local budget. Waiting reads the
|
|
7
|
+
accepted run's status and result routes, retrying those reads inside one local budget.
|
|
7
8
|
"""
|
|
8
9
|
|
|
9
10
|
from __future__ import annotations
|
|
@@ -40,6 +41,11 @@ _UNBOUNDED_POST_READ = 60.0
|
|
|
40
41
|
# retried rather than consuming the whole budget.
|
|
41
42
|
_READ_TIMEOUT = 30.0
|
|
42
43
|
_FIRST_POLL_DELAY = 0.5
|
|
44
|
+
# Attempts to open the POST's connection, and the first pause between them, which
|
|
45
|
+
# doubles. A connection that never opened sent nothing, so another attempt cannot
|
|
46
|
+
# submit a second run.
|
|
47
|
+
_CONNECT_ATTEMPTS = 3
|
|
48
|
+
_FIRST_CONNECT_DELAY = 0.5
|
|
43
49
|
_MAX_POLL_DELAY = 5.0
|
|
44
50
|
# A server poll hint is honored up to this many seconds.
|
|
45
51
|
_MAX_RETRY_AFTER = 60.0
|
|
@@ -100,6 +106,30 @@ class RunSubmissionUncertain(RuntimeError):
|
|
|
100
106
|
_set_run_id(self, run_id)
|
|
101
107
|
|
|
102
108
|
|
|
109
|
+
class RunNotSubmitted(RunSubmissionUncertain):
|
|
110
|
+
"""No connection to serve opened, so the POST sent nothing and no run exists.
|
|
111
|
+
|
|
112
|
+
``endpoint`` is the address the SDK could not connect to, and the message gives
|
|
113
|
+
the transport's reason, such as a refused connection. Submitting again is safe.
|
|
114
|
+
|
|
115
|
+
A ``RunSubmissionUncertain`` so a caller that handles the uncertain outcome
|
|
116
|
+
still catches it. Its recovery, inspecting the run list before submitting
|
|
117
|
+
again, is unnecessary here but never wrong.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(self, deployment_id: str, endpoint: str, *, attempts: int, cause: BaseException):
|
|
121
|
+
reason = str(cause) or type(cause).__name__
|
|
122
|
+
RuntimeError.__init__(
|
|
123
|
+
self,
|
|
124
|
+
f"Deployment {deployment_id} was not submitted: no connection to {endpoint} opened "
|
|
125
|
+
f"in {attempts} attempt(s) ({reason}). Nothing was sent, so submitting again is safe.",
|
|
126
|
+
)
|
|
127
|
+
self.deployment_id = deployment_id
|
|
128
|
+
self.endpoint = endpoint
|
|
129
|
+
self.status_code = None
|
|
130
|
+
_set_run_id(self, None)
|
|
131
|
+
|
|
132
|
+
|
|
103
133
|
def _cancel_command(run_id: str) -> str:
|
|
104
134
|
return f"cmpnd deployments runs cancel {run_id}"
|
|
105
135
|
|
|
@@ -387,24 +417,42 @@ class _RunClient:
|
|
|
387
417
|
return response
|
|
388
418
|
|
|
389
419
|
def submit(self, deployment_id: str, body: dict[str, Any], deadline: float | None, *, wait: bool) -> dict[str, Any]:
|
|
390
|
-
"""Send the one POST.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
f"
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
420
|
+
"""Send the one POST.
|
|
421
|
+
|
|
422
|
+
Never repeated once a connection opened: a repeat would be a second paid run. A
|
|
423
|
+
connection that never opened sent nothing, so it is attempted again while the
|
|
424
|
+
budget allows, and then raises ``RunNotSubmitted``.
|
|
425
|
+
"""
|
|
426
|
+
attempt = 0
|
|
427
|
+
while True:
|
|
428
|
+
attempt += 1
|
|
429
|
+
remaining = _remaining(deadline)
|
|
430
|
+
if remaining is not None and remaining <= 0:
|
|
431
|
+
raise TimeoutError(f"The local budget ran out before deployment {deployment_id} was submitted")
|
|
432
|
+
prefer = server_wait(remaining) if wait else 0
|
|
433
|
+
# The read timeout outlasts the server wait, so the transport never gives
|
|
434
|
+
# up while serve is still holding an accepted run's reply.
|
|
435
|
+
read_timeout = remaining if remaining is not None else prefer + _UNBOUNDED_POST_READ
|
|
436
|
+
try:
|
|
437
|
+
response = self._send(
|
|
438
|
+
"POST",
|
|
439
|
+
f"/api/v1/deployments/{deployment_id}/runs",
|
|
440
|
+
timeout=read_timeout,
|
|
441
|
+
body=body,
|
|
442
|
+
headers={"Prefer": f"wait={prefer}"} if prefer > 0 else None,
|
|
443
|
+
)
|
|
444
|
+
break
|
|
445
|
+
# httpx raises these two only while it opens a connection, before any byte
|
|
446
|
+
# of the request is written. Every other transport error may follow a sent
|
|
447
|
+
# request, so it leaves acceptance uncertain.
|
|
448
|
+
except (httpx.ConnectError, httpx.ConnectTimeout) as exc:
|
|
449
|
+
pause = _jitter(_FIRST_CONNECT_DELAY * 2 ** (attempt - 1))
|
|
450
|
+
left = _remaining(deadline)
|
|
451
|
+
if attempt >= _CONNECT_ATTEMPTS or (left is not None and left <= pause):
|
|
452
|
+
raise RunNotSubmitted(deployment_id, self.endpoint, attempts=attempt, cause=exc) from exc
|
|
453
|
+
_sleep(pause)
|
|
454
|
+
except httpx.RequestError as exc:
|
|
455
|
+
raise RunSubmissionUncertain(deployment_id) from exc
|
|
408
456
|
if response.status_code >= 500:
|
|
409
457
|
raise RunSubmissionUncertain(
|
|
410
458
|
deployment_id,
|
|
@@ -291,9 +291,11 @@ def _raise_stored_failure(run_id: str, result: object, endpoint: str) -> None:
|
|
|
291
291
|
provider_failure = _retryable_provider_failure(response)
|
|
292
292
|
if provider_failure is not None:
|
|
293
293
|
provider_status, attempts, retry_after = provider_failure
|
|
294
|
+
# The worker's status says only that the run failed, and the provider's own
|
|
295
|
+
# status is in the detail, so the message leaves the worker's out.
|
|
294
296
|
raise _with_run_id(
|
|
295
297
|
RetryableProviderError(
|
|
296
|
-
|
|
298
|
+
f"Deployment run {run_id} failed" + (f": {detail}" if detail else ""),
|
|
297
299
|
request=request,
|
|
298
300
|
response=response,
|
|
299
301
|
provider_status=provider_status,
|
|
@@ -457,7 +457,15 @@ Serve's not-ready `409` and `422` refusals keep the `RuntimeError` type and
|
|
|
457
457
|
message that `run_deployment()` raises, and are `httpx.HTTPStatusError` too. A
|
|
458
458
|
lost POST reply or a server `5xx` leaves acceptance uncertain, so the SDK raises
|
|
459
459
|
`RunSubmissionUncertain` with `status_code` set when serve answered. Its message
|
|
460
|
-
names the command to list recent runs.
|
|
460
|
+
names the command to list recent runs. A connection that never opened sent
|
|
461
|
+
nothing: httpx raises `ConnectError` or `ConnectTimeout` only before any byte of
|
|
462
|
+
the request is written. The SDK tries the POST up to three times, pausing about
|
|
463
|
+
half a second and then a second, and stops early when the pause would outlast
|
|
464
|
+
the budget. Then it raises `RunNotSubmitted`, which names the endpoint and the
|
|
465
|
+
transport's reason, such as a refused connection, and says submitting again is
|
|
466
|
+
safe. `RunNotSubmitted` subclasses `RunSubmissionUncertain`, so a handler for the
|
|
467
|
+
uncertain case still catches it. A read timeout, a write failure or a broken
|
|
468
|
+
reply may follow a sent request, so each stays uncertain. Reads that time out or answer `408`,
|
|
461
469
|
`429` or `5xx` are retried with backoff and jitter, honoring `Retry-After`. A
|
|
462
470
|
`401`, `403` or `404` read raises at once. A spent budget raises
|
|
463
471
|
`RunWaitTimeout`, and the accepted run continues. Its `status` and
|
|
@@ -477,7 +485,11 @@ the same metadata, for a completed run's prediction and a failed run's error.
|
|
|
477
485
|
trace, when the server names none, and when the run failed before serve
|
|
478
486
|
accepted it. A
|
|
479
487
|
retained provider failure keeps its structured `RetryableProviderError` type but
|
|
480
|
-
does not start another run.
|
|
488
|
+
does not start another run. Its message is the provider's outage as the egress
|
|
489
|
+
service reported it, such as `Deployment run dr_… failed: the provider at
|
|
490
|
+
gw.lunaroute.com was unavailable: 3 attempt(s) over 3m1.367s; its last answer was
|
|
491
|
+
503: backend unavailable`. It leaves out the worker's status, which the exception's
|
|
492
|
+
`response` still carries, and the run's `error_code` is `ProviderUnavailable`. Trace delivery can finish after the result is
|
|
481
493
|
available.
|
|
482
494
|
|
|
483
495
|
Call `client.submit_deployment_run(deployment, inputs)` to accept work without a
|
|
@@ -5,7 +5,7 @@ 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.81.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -199,6 +199,95 @@ def test_execute_never_repeats_uncertain_post(monkeypatch: pytest.MonkeyPatch, f
|
|
|
199
199
|
assert [req.method for req in seen] == ["POST"]
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
@pytest.mark.parametrize(
|
|
203
|
+
("failure", "cause"),
|
|
204
|
+
[
|
|
205
|
+
(httpx.ConnectError, "[Errno 61] Connection refused"),
|
|
206
|
+
(httpx.ConnectTimeout, "timed out"),
|
|
207
|
+
],
|
|
208
|
+
)
|
|
209
|
+
def test_a_connection_that_never_opened_submitted_nothing(
|
|
210
|
+
monkeypatch: pytest.MonkeyPatch, failure: type[httpx.TransportError], cause: str
|
|
211
|
+
):
|
|
212
|
+
seen: list[httpx.Request] = []
|
|
213
|
+
|
|
214
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
215
|
+
seen.append(req)
|
|
216
|
+
raise failure(cause, request=req)
|
|
217
|
+
|
|
218
|
+
_transport(monkeypatch, answer)
|
|
219
|
+
_clock(monkeypatch)
|
|
220
|
+
with pytest.raises(deployment_runs.RunNotSubmitted) as caught:
|
|
221
|
+
_client().run_deployment(DEPLOYMENT_ID, question="hi")
|
|
222
|
+
error = caught.value
|
|
223
|
+
assert str(error) == (
|
|
224
|
+
f"Deployment {DEPLOYMENT_ID} was not submitted: no connection to https://example.test opened "
|
|
225
|
+
f"in {len(seen)} attempt(s) ({cause}). Nothing was sent, so submitting again is safe."
|
|
226
|
+
)
|
|
227
|
+
assert error.endpoint == "https://example.test"
|
|
228
|
+
assert error.deployment_id == DEPLOYMENT_ID
|
|
229
|
+
assert error.status_code is None
|
|
230
|
+
assert isinstance(error.__cause__, failure)
|
|
231
|
+
assert _client().deployment_run_id(error) is None
|
|
232
|
+
# A caller that already handles the uncertain outcome still catches it: inspecting
|
|
233
|
+
# the run list before resubmitting is unnecessary here, never wrong.
|
|
234
|
+
assert isinstance(error, deployment_runs.RunSubmissionUncertain)
|
|
235
|
+
assert cmpnd.RunNotSubmitted is deployment_runs.RunNotSubmitted
|
|
236
|
+
assert [req.method for req in seen] == ["POST"] * deployment_runs._CONNECT_ATTEMPTS
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def test_a_connection_that_opens_on_a_later_attempt_submits_once(monkeypatch: pytest.MonkeyPatch):
|
|
240
|
+
seen: list[str] = []
|
|
241
|
+
|
|
242
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
243
|
+
seen.append(req.method)
|
|
244
|
+
if len(seen) == 1:
|
|
245
|
+
raise httpx.ConnectError("[Errno 61] Connection refused", request=req)
|
|
246
|
+
if req.method == "POST":
|
|
247
|
+
return httpx.Response(200, json=_run("completed", {"output": {"answer": "ready"}}), request=req)
|
|
248
|
+
raise AssertionError(f"unexpected {req.method}")
|
|
249
|
+
|
|
250
|
+
_transport(monkeypatch, answer)
|
|
251
|
+
_clock(monkeypatch)
|
|
252
|
+
assert _client().run_deployment(DEPLOYMENT_ID, question="hi").answer == "ready"
|
|
253
|
+
assert seen == ["POST", "POST"]
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def test_a_refused_connection_is_not_retried_past_the_budget(monkeypatch: pytest.MonkeyPatch):
|
|
257
|
+
seen: list[httpx.Request] = []
|
|
258
|
+
now = _clock(monkeypatch)
|
|
259
|
+
|
|
260
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
261
|
+
seen.append(req)
|
|
262
|
+
now[0] += 1.0
|
|
263
|
+
raise httpx.ConnectError("[Errno 61] Connection refused", request=req)
|
|
264
|
+
|
|
265
|
+
_transport(monkeypatch, answer)
|
|
266
|
+
with pytest.raises(deployment_runs.RunNotSubmitted, match="in 1 attempt"):
|
|
267
|
+
_client().run_deployment(DEPLOYMENT_ID, timeout=1.2, question="hi")
|
|
268
|
+
assert len(seen) == 1
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@pytest.mark.parametrize(
|
|
272
|
+
"failure",
|
|
273
|
+
[httpx.ReadTimeout, httpx.ReadError, httpx.WriteError, httpx.WriteTimeout, httpx.RemoteProtocolError],
|
|
274
|
+
)
|
|
275
|
+
def test_a_failure_after_the_connection_opened_stays_uncertain(
|
|
276
|
+
monkeypatch: pytest.MonkeyPatch, failure: type[httpx.TransportError]
|
|
277
|
+
):
|
|
278
|
+
seen: list[httpx.Request] = []
|
|
279
|
+
|
|
280
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
281
|
+
seen.append(req)
|
|
282
|
+
raise failure("lost", request=req)
|
|
283
|
+
|
|
284
|
+
_transport(monkeypatch, answer)
|
|
285
|
+
with pytest.raises(deployment_runs.RunSubmissionUncertain, match="uncertain") as caught:
|
|
286
|
+
_client().run_deployment(DEPLOYMENT_ID, question="hi")
|
|
287
|
+
assert not isinstance(caught.value, deployment_runs.RunNotSubmitted)
|
|
288
|
+
assert len(seen) == 1
|
|
289
|
+
|
|
290
|
+
|
|
202
291
|
def test_wait_polls_after_accepted_response_without_resubmitting(monkeypatch: pytest.MonkeyPatch):
|
|
203
292
|
seen: list[str] = []
|
|
204
293
|
replies = [
|
|
@@ -272,6 +272,37 @@ def test_execute_stored_failure_preserves_run_id_and_provider_type(monkeypatch:
|
|
|
272
272
|
assert type(caught.value) is httpx.HTTPStatusError
|
|
273
273
|
|
|
274
274
|
|
|
275
|
+
OUTAGE = (
|
|
276
|
+
"the provider at gw.lunaroute.com was unavailable: 3 attempt(s) over 3m1.367s; "
|
|
277
|
+
"its last answer was 503: backend unavailable"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def test_a_provider_outage_reads_as_the_providers_and_names_no_platform_status(monkeypatch: pytest.MonkeyPatch):
|
|
282
|
+
failure = {
|
|
283
|
+
"error": {"type": "ProviderUnavailable", "message": OUTAGE},
|
|
284
|
+
"execution_status": 500,
|
|
285
|
+
"retryable": True,
|
|
286
|
+
"retry_after": 120,
|
|
287
|
+
"failure": {"domain": "provider", "class": "provider_unavailable", "upstream_status": 503, "attempts": 3},
|
|
288
|
+
}
|
|
289
|
+
_transport(monkeypatch, lambda req: httpx.Response(200, json=_run("failed", failure), request=req))
|
|
290
|
+
with pytest.raises(execution.RetryableProviderError) as caught:
|
|
291
|
+
_client().run_deployment("d_ready")
|
|
292
|
+
assert str(caught.value) == f"Deployment run {RUN_ID} failed: {OUTAGE}"
|
|
293
|
+
# The status stays on the exception for a caller that reads it.
|
|
294
|
+
assert caught.value.response.status_code == 500
|
|
295
|
+
assert (caught.value.provider_status, caught.value.attempts, caught.value.retry_after) == (503, 3, 120)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def test_a_failure_that_is_not_the_providers_keeps_its_status(monkeypatch: pytest.MonkeyPatch):
|
|
299
|
+
failure = {"error": {"type": "RunFailed", "message": "KeyError: 'answer'"}, "execution_status": 500}
|
|
300
|
+
_transport(monkeypatch, lambda req: httpx.Response(200, json=_run("failed", failure), request=req))
|
|
301
|
+
with pytest.raises(httpx.HTTPStatusError) as caught:
|
|
302
|
+
_client().run_deployment("d_ready")
|
|
303
|
+
assert str(caught.value) == f"Deployment run {RUN_ID} failed with 500: KeyError: 'answer'"
|
|
304
|
+
|
|
305
|
+
|
|
275
306
|
class TestDeployedProgram:
|
|
276
307
|
def test_identity_and_repr(self):
|
|
277
308
|
deployed = execution.DeployedProgram("d_ready")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|