cmpnd 0.80.0__tar.gz → 0.82.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.82.0}/PKG-INFO +4 -1
- {cmpnd-0.80.0 → cmpnd-0.82.0}/README.md +3 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/__init__.py +2 -1
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/optimizations.py +220 -6
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/client.py +3 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/deployment_runs.py +70 -22
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/execution.py +3 -1
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/cli.md +33 -2
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/sdk-instrumentation.md +14 -2
- {cmpnd-0.80.0 → cmpnd-0.82.0}/pyproject.toml +1 -1
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_optimizations.py +210 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deployment_runs.py +89 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_execute.py +31 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/uv.lock +1 -1
- {cmpnd-0.80.0 → cmpnd-0.82.0}/.gitignore +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/AGENTS.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/CLAUDE.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/context.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/program_naming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/client.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/README.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/drain.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_client.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_context.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_eval.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_eval_program_id.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_integration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_models.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_no_signature_hash_on_the_wire.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimization_phase_callback.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimization_program_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_program_naming.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_retry.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.80.0 → cmpnd-0.82.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.82.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",
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
from argparse import ArgumentParser, _SubParsersAction
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from .. import api_client, deprecation, pagination
|
|
9
|
+
from .. import api_client, deprecation, pagination, views
|
|
10
10
|
from . import top
|
|
11
11
|
|
|
12
12
|
|
|
@@ -20,6 +20,7 @@ def _add_list_args(p: ArgumentParser) -> None:
|
|
|
20
20
|
p.add_argument("--optimizer-type", help="Filter by optimizer type")
|
|
21
21
|
p.add_argument("--min-score", type=float, help="Minimum best score")
|
|
22
22
|
pagination.add_args(p, with_page_aliases=True, default_limit=50)
|
|
23
|
+
views.add_text_flag(p)
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def _add_comparability_args(p: ArgumentParser) -> None:
|
|
@@ -172,7 +173,8 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
172
173
|
failed.set_defaults(func=handle_compare_failed_examples)
|
|
173
174
|
|
|
174
175
|
iters = sub.add_parser("iterations", help="List iterations for an optimization run")
|
|
175
|
-
iters.add_argument("id", help="Optimization run ID (
|
|
176
|
+
iters.add_argument("id", help="Optimization run ID (op_...)")
|
|
177
|
+
views.add_text_flag(iters)
|
|
176
178
|
iters.set_defaults(func=handle_iterations)
|
|
177
179
|
|
|
178
180
|
cands = sub.add_parser(
|
|
@@ -187,6 +189,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
187
189
|
"optimization actually wrote. Off by default: the text dwarfs the metrics, "
|
|
188
190
|
"and listing candidates is usually how you find the one worth reading",
|
|
189
191
|
)
|
|
192
|
+
views.add_text_flag(cands)
|
|
190
193
|
cands.set_defaults(func=handle_candidates)
|
|
191
194
|
|
|
192
195
|
compiled = sub.add_parser(
|
|
@@ -226,7 +229,11 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
226
229
|
|
|
227
230
|
def handle_list(client: api_client.ApiClient, args: Any) -> Any:
|
|
228
231
|
if getattr(args, "status", None) == "queued":
|
|
229
|
-
|
|
232
|
+
payload = _list_queued(client, args)
|
|
233
|
+
if getattr(args, "text", False):
|
|
234
|
+
_render_queued(payload)
|
|
235
|
+
return None
|
|
236
|
+
return payload
|
|
230
237
|
# This route paginates by page/per_page; the shared helper maps the
|
|
231
238
|
# user-facing --limit/--offset onto that pair.
|
|
232
239
|
body: dict[str, Any] = pagination.wire(args, "per_page")
|
|
@@ -239,7 +246,112 @@ def handle_list(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
239
246
|
val = getattr(args, attr, None)
|
|
240
247
|
if val is not None:
|
|
241
248
|
body[key] = val
|
|
242
|
-
|
|
249
|
+
payload = client.post("/api/v1/optimizations/search", json=body)
|
|
250
|
+
if getattr(args, "text", False):
|
|
251
|
+
_render_runs(payload)
|
|
252
|
+
return None
|
|
253
|
+
return payload
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# The statuses of a run that has not settled. Serve's open set: `interrupted` is open and
|
|
257
|
+
# not progressing, and any delivered progress returns it to `running`.
|
|
258
|
+
_OPEN_STATUSES = ("running", "interrupted")
|
|
259
|
+
|
|
260
|
+
# What a cell shows for a value serve does not hold. Never a zero: a zero is a value.
|
|
261
|
+
_UNRECORDED = "-"
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _rows(payload: Any, key: str) -> list[dict[str, Any]]:
|
|
265
|
+
items = payload.get(key) if isinstance(payload, dict) else None
|
|
266
|
+
return [item for item in items or [] if isinstance(item, dict)]
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _table(header: tuple[str, ...], rows: list[tuple[str, ...]]) -> None:
|
|
270
|
+
"""Print rows under a header, each column as wide as its widest cell."""
|
|
271
|
+
widths = [max(len(row[i]) for row in [header, *rows]) for i in range(len(header))]
|
|
272
|
+
for row in [header, *rows]:
|
|
273
|
+
print(" ".join(cell.ljust(widths[i]) for i, cell in enumerate(row)).rstrip())
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _score(value: Any) -> str:
|
|
277
|
+
return f"{value:.3f}" if isinstance(value, (int, float)) and not isinstance(value, bool) else _UNRECORDED
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _int(value: Any) -> str:
|
|
281
|
+
return str(value) if isinstance(value, int) and not isinstance(value, bool) else _UNRECORDED
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _metric_calls(run: dict[str, Any]) -> str:
|
|
285
|
+
"""Metric calls spent of the budget. An open run reads its live counter, which serve
|
|
286
|
+
keeps the total in step with; a settled run reads its total."""
|
|
287
|
+
used = run.get("total_metric_calls")
|
|
288
|
+
live = run.get("current_metric_calls")
|
|
289
|
+
if isinstance(live, int) and (not isinstance(used, int) or live > used):
|
|
290
|
+
used = live
|
|
291
|
+
budget = run.get("max_metric_calls")
|
|
292
|
+
if not isinstance(used, int):
|
|
293
|
+
return _UNRECORDED
|
|
294
|
+
return f"{used}/{budget}" if isinstance(budget, int) and budget > 0 else str(used)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _best_score(run: dict[str, Any]) -> str:
|
|
298
|
+
"""The run's best score. Serve sends `best_score` as zero until the run records one,
|
|
299
|
+
and flags that with `best_score_recorded: false`. A serve that sends no flag leaves
|
|
300
|
+
an unrecorded score indistinguishable from a measured zero, so the score shows."""
|
|
301
|
+
if run.get("best_score_recorded") is False:
|
|
302
|
+
return _UNRECORDED
|
|
303
|
+
return _score(run.get("best_score"))
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _verdicts(run: dict[str, Any]) -> str:
|
|
307
|
+
"""Accepted and rejected proposals, as the run's producer counted them. A run that
|
|
308
|
+
never reported them shows a dash rather than 0/0."""
|
|
309
|
+
accepted, rejected = run.get("candidates_accepted"), run.get("candidates_rejected")
|
|
310
|
+
if accepted is None and rejected is None:
|
|
311
|
+
return _UNRECORDED
|
|
312
|
+
return f"{_int(accepted)}/{_int(rejected)}"
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _render_runs(payload: Any) -> None:
|
|
316
|
+
runs = _rows(payload, "optimization_runs")
|
|
317
|
+
if not runs:
|
|
318
|
+
print("No optimization runs match.")
|
|
319
|
+
return
|
|
320
|
+
rows = [
|
|
321
|
+
(
|
|
322
|
+
str(run.get("run_id") or ""),
|
|
323
|
+
str(run.get("status") or ""),
|
|
324
|
+
str(run.get("program_name") or _UNRECORDED),
|
|
325
|
+
str(run.get("optimizer_type") or ""),
|
|
326
|
+
_metric_calls(run),
|
|
327
|
+
_verdicts(run),
|
|
328
|
+
_best_score(run),
|
|
329
|
+
str(run.get("start_time") or ""),
|
|
330
|
+
)
|
|
331
|
+
for run in runs
|
|
332
|
+
]
|
|
333
|
+
_table(("RUN", "STATUS", "PROGRAM", "OPTIMIZER", "METRIC CALLS", "ACCEPTED/REJECTED", "BEST", "STARTED"), rows)
|
|
334
|
+
total = payload.get("total") if isinstance(payload, dict) else None
|
|
335
|
+
if isinstance(total, int) and total > len(runs):
|
|
336
|
+
print(f"{len(runs)} of {total} runs. Page with --limit and --offset.")
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _render_queued(payload: Any) -> None:
|
|
340
|
+
queued = _rows(payload, "optimizations")
|
|
341
|
+
if not queued:
|
|
342
|
+
print("No optimization runs are queued.")
|
|
343
|
+
return
|
|
344
|
+
rows = [
|
|
345
|
+
(
|
|
346
|
+
_int(run.get("position")),
|
|
347
|
+
str(run.get("optimization_id") or ""),
|
|
348
|
+
str(run.get("status") or "queued"),
|
|
349
|
+
str(run.get("optimizer") or ""),
|
|
350
|
+
str(run.get("created_at") or ""),
|
|
351
|
+
)
|
|
352
|
+
for run in queued
|
|
353
|
+
]
|
|
354
|
+
_table(("POSITION", "RUN", "STATUS", "OPTIMIZER", "QUEUED AT"), rows)
|
|
243
355
|
|
|
244
356
|
|
|
245
357
|
def _list_queued(client: api_client.ApiClient, args: Any) -> Any:
|
|
@@ -370,12 +482,114 @@ def handle_compare_failed_examples(client: api_client.ApiClient, args: Any) -> A
|
|
|
370
482
|
|
|
371
483
|
|
|
372
484
|
def handle_iterations(client: api_client.ApiClient, args: Any) -> Any:
|
|
373
|
-
|
|
485
|
+
payload = client.get(f"/api/v1/optimizations/{args.id}/iterations")
|
|
486
|
+
if not getattr(args, "text", False):
|
|
487
|
+
return payload
|
|
488
|
+
_render_iterations(args.id, payload)
|
|
489
|
+
return None
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def _verdict(iteration: dict[str, Any]) -> str:
|
|
493
|
+
accepted = iteration.get("accepted")
|
|
494
|
+
if accepted is None:
|
|
495
|
+
return _UNRECORDED
|
|
496
|
+
return "accepted" if accepted else "rejected"
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def _result(iteration: dict[str, Any]) -> str:
|
|
500
|
+
"""The candidate an accepted proposal became, with its validation score."""
|
|
501
|
+
idx = iteration.get("result_candidate_idx")
|
|
502
|
+
if not isinstance(idx, int):
|
|
503
|
+
return _UNRECORDED
|
|
504
|
+
score = iteration.get("validation_score")
|
|
505
|
+
return f"{idx} ({_score(score)})" if isinstance(score, (int, float)) else str(idx)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def _render_iterations(run_id: str, payload: Any) -> None:
|
|
509
|
+
"""One row per iteration: the candidate it mutated and that candidate's minibatch mean,
|
|
510
|
+
the proposal's mean over the same minibatch, gepa's verdict, and the candidate an
|
|
511
|
+
accepted proposal became. A dash is a value serve does not hold for that iteration."""
|
|
512
|
+
iterations = _rows(payload, "iterations")
|
|
513
|
+
if not iterations:
|
|
514
|
+
print(f"{run_id} has no iterations yet.")
|
|
515
|
+
return
|
|
516
|
+
rows = [
|
|
517
|
+
(
|
|
518
|
+
_int(it.get("idx")),
|
|
519
|
+
_int(it.get("parent_candidate_idx")),
|
|
520
|
+
str(it.get("batch_size") or _UNRECORDED),
|
|
521
|
+
_score(it.get("parent_minibatch_score")),
|
|
522
|
+
_score(it.get("proposal_minibatch_score")),
|
|
523
|
+
_verdict(it),
|
|
524
|
+
_result(it),
|
|
525
|
+
str(it.get("duration") or _UNRECORDED),
|
|
526
|
+
)
|
|
527
|
+
for it in iterations
|
|
528
|
+
]
|
|
529
|
+
_table(
|
|
530
|
+
("ITER", "PARENT", "BATCH", "PARENT SCORE", "PROPOSAL SCORE", "VERDICT", "CANDIDATE", "DURATION"),
|
|
531
|
+
rows,
|
|
532
|
+
)
|
|
533
|
+
print(
|
|
534
|
+
"Scores are means over the iteration's minibatch. CANDIDATE is the candidate an accepted "
|
|
535
|
+
"proposal became, with its validation score."
|
|
536
|
+
)
|
|
537
|
+
if any(_UNRECORDED in row[1:] for row in rows):
|
|
538
|
+
print(
|
|
539
|
+
f"{_UNRECORDED}: not recorded for that iteration. An open run holds what its optimizer "
|
|
540
|
+
"has reported so far, and the settled record fills the rest."
|
|
541
|
+
)
|
|
374
542
|
|
|
375
543
|
|
|
376
544
|
def handle_candidates(client: api_client.ApiClient, args: Any) -> Any:
|
|
377
545
|
params = {"include": "instructions"} if getattr(args, "full", False) else None
|
|
378
|
-
|
|
546
|
+
payload = client.get(f"/api/v1/optimizations/{args.id}/candidates", params=params)
|
|
547
|
+
if not getattr(args, "text", False):
|
|
548
|
+
return payload
|
|
549
|
+
_render_candidates(args.id, payload, full=getattr(args, "full", False))
|
|
550
|
+
return None
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def _origin(candidate: dict[str, Any]) -> str:
|
|
554
|
+
"""How the candidate entered the pool. The seed starts it; every other candidate came
|
|
555
|
+
from an accepted proposal, a reflective mutation or a merge."""
|
|
556
|
+
if "accepted" not in candidate or candidate.get("mutation_type") == "seed":
|
|
557
|
+
return "seed"
|
|
558
|
+
return f"accepted ({candidate.get('mutation_type') or 'proposal'})"
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
def _render_candidates(run_id: str, payload: Any, *, full: bool) -> None:
|
|
562
|
+
candidates = _rows(payload, "candidates")
|
|
563
|
+
status = payload.get("run_status") if isinstance(payload, dict) else None
|
|
564
|
+
summary = [f"{run_id}: {status}" if status else run_id]
|
|
565
|
+
if isinstance(payload, dict) and ("candidates_accepted" in payload or "candidates_rejected" in payload):
|
|
566
|
+
summary.append(
|
|
567
|
+
f"{_int(payload.get('candidates_accepted'))} accepted, {_int(payload.get('candidates_rejected'))} rejected"
|
|
568
|
+
)
|
|
569
|
+
summary.append(f"{len(candidates)} candidate{'' if len(candidates) == 1 else 's'} listed")
|
|
570
|
+
print(" · ".join(summary))
|
|
571
|
+
if candidates:
|
|
572
|
+
rows = [
|
|
573
|
+
(
|
|
574
|
+
str(c.get("candidate_id") or ""),
|
|
575
|
+
_int(c.get("candidate_idx", c.get("idx"))),
|
|
576
|
+
_int(c.get("parent_candidate_idx")),
|
|
577
|
+
str(c.get("generation") or _UNRECORDED),
|
|
578
|
+
_score(c.get("aggregate_score")),
|
|
579
|
+
_origin(c),
|
|
580
|
+
"yes" if c.get("is_pareto_member") else "",
|
|
581
|
+
)
|
|
582
|
+
for c in candidates
|
|
583
|
+
]
|
|
584
|
+
_table(("CANDIDATE", "IDX", "PARENT", "GEN", "VAL SCORE", "ORIGIN", "PARETO"), rows)
|
|
585
|
+
if full:
|
|
586
|
+
for c in candidates:
|
|
587
|
+
print(f"{c.get('candidate_id')}: {_first_line(_instruction_texts(c.get('instructions')))}")
|
|
588
|
+
if status in _OPEN_STATUSES:
|
|
589
|
+
print(
|
|
590
|
+
"The run is open: the list grows as the optimizer reports each candidate it accepts, "
|
|
591
|
+
"and the settled record completes it."
|
|
592
|
+
)
|
|
379
593
|
|
|
380
594
|
|
|
381
595
|
def handle_compiled_program(client: api_client.ApiClient, args: Any) -> Any:
|
|
@@ -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,
|
|
@@ -190,8 +190,9 @@ does the same.
|
|
|
190
190
|
A namespaced read, such as `cmpnd traces show`, `cmpnd deployments list` or
|
|
191
191
|
`cmpnd tool-servers list`, prints the API's JSON by default, so a script can
|
|
192
192
|
pipe it to `jq`. A human view is an opt-in flag: `--tree` and `--timeline` on
|
|
193
|
-
`traces show`, and `--text` on `tool-servers list`, `tool-servers show
|
|
194
|
-
`credentials list
|
|
193
|
+
`traces show`, and `--text` on `tool-servers list`, `tool-servers show`,
|
|
194
|
+
`credentials list`, `optimizations list`, `optimizations iterations` and
|
|
195
|
+
`optimizations candidates`. Those accept `--json` as well, so older scripts keep
|
|
195
196
|
working. An action command may print a short result and take `--json` for the
|
|
196
197
|
whole answer: `cmpnd programs create` prints the new id, and
|
|
197
198
|
`cmpnd optimizations continue` prints the best deployment. The top-level
|
|
@@ -798,6 +799,36 @@ live objects and takes named models through its `lms` argument. An authored file
|
|
|
798
799
|
binding cannot be combined with `lms` in the parent call or `config["lms"]`.
|
|
799
800
|
The CLI has no named-model flag.
|
|
800
801
|
|
|
802
|
+
### Watch a run
|
|
803
|
+
|
|
804
|
+
A hosted run reports its progress while it runs, so these reads show an open
|
|
805
|
+
run as it is. Each prints the API's JSON, and `--text` renders a table.
|
|
806
|
+
|
|
807
|
+
- `cmpnd optimizations list --text` shows each run's status, its metric calls
|
|
808
|
+
of the budget, its accepted and rejected proposals and its best score. The
|
|
809
|
+
JSON's `total_metric_calls` keeps pace with `current_metric_calls` while the
|
|
810
|
+
run is open, and `total_candidates` counts the candidates the platform holds
|
|
811
|
+
for it, which `candidates` lists. `best_score` reads 0 until the run
|
|
812
|
+
records a score, and `best_score_recorded` is `false` until then, so
|
|
813
|
+
`--text` shows a dash. `show` and `list` read the same row, so they agree.
|
|
814
|
+
- `cmpnd optimizations iterations RUN_ID` lists each iteration: the candidate
|
|
815
|
+
it mutated (`parent_candidate_idx`) and that candidate's mean over the
|
|
816
|
+
iteration's minibatch (`parent_minibatch_score`), the proposal's mean over the
|
|
817
|
+
same minibatch (`proposal_minibatch_score`), whether gepa `accepted` it, the
|
|
818
|
+
candidate an accepted proposal became (`result_candidate_idx`) with its
|
|
819
|
+
`validation_score`, and its `batch_size` and `duration_ms`. A field the
|
|
820
|
+
platform does not hold for an iteration is left out, and `--text` shows a
|
|
821
|
+
dash. A run the SDK tracks on your machine reports only each iteration's
|
|
822
|
+
number and score until it settles.
|
|
823
|
+
- `cmpnd optimizations candidates RUN_ID` lists every candidate the run holds,
|
|
824
|
+
beside its `run_status` and its `candidates_accepted` and
|
|
825
|
+
`candidates_rejected` counts. An open hosted run lists each candidate as the
|
|
826
|
+
optimizer accepts it, and the settled record completes the list and keeps
|
|
827
|
+
each `ca_` id. A run the SDK tracks lists its candidates once it settles.
|
|
828
|
+
The seed carries no `accepted`, because no verdict admitted it.
|
|
829
|
+
- `cmpnd optimizations show RUN_ID` names the run's `reflection_model_name`
|
|
830
|
+
from the moment it starts.
|
|
831
|
+
|
|
801
832
|
### Cancel a run
|
|
802
833
|
|
|
803
834
|
`cmpnd optimizations cancel RUN_ID` stops an open run and keeps its record,
|
|
@@ -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.82.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|