cmpnd 0.64.0__tar.gz → 0.65.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.64.0 → cmpnd-0.65.0}/PKG-INFO +24 -6
- {cmpnd-0.64.0 → cmpnd-0.65.0}/README.md +23 -5
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/optimizations.py +117 -2
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/top.py +18 -26
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/shell.py +0 -4
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/verbs.py +1 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/client.py +86 -20
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/execution.py +4 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimization.py +192 -116
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/cli.md +35 -3
- {cmpnd-0.64.0 → cmpnd-0.65.0}/pyproject.toml +1 -1
- cmpnd-0.65.0/tests/e2e/continuation_task.py +72 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_pandas.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_authored_metric.py +0 -2
- cmpnd-0.65.0/tests/e2e/test_optimize_continuation.py +120 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_custom_proposer.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_failures.py +0 -2
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_loop.py +0 -3
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/hosted_optimize_probe.py +0 -1
- cmpnd-0.65.0/tests/stress/test_optimize_continuation.py +156 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_optimize_loop.py +1 -2
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_optimize_loop_wasm.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_optimize_stress.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored_binding_credentials.py +3 -3
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored_metric_contract.py +5 -5
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored_named_models.py +0 -2
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored_optimize.py +3 -3
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_optimizations.py +96 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_top.py +4 -3
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_credential_selection.py +6 -6
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deploy_program_id.py +11 -14
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_lm_configuration.py +1 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize.py +272 -81
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_budget.py +3 -4
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_proposer.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_program_names_in_deploy.py +3 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/uv.lock +1 -1
- {cmpnd-0.64.0 → cmpnd-0.65.0}/.gitignore +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/AGENTS.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/CLAUDE.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/context.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/models.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/client.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/docs/sdk-instrumentation.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/README.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/release-stress.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/drain.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/_provider.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/_reliability.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/_result.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/mint_bedrock_token.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_bedrock_converse.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_deploy_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_multi_client_stress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_optimize_client_committee.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_provider_roles.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_real_provider_twins.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_reliability.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_reliability_classify.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_rlm_wasm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/stress/test_trace_search.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_context.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_eval.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_execute.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_integration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_models.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_release_stress_script.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.65.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.65.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>
|
|
@@ -497,14 +497,12 @@ sdk.optimize_deployment(
|
|
|
497
497
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
498
498
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
499
499
|
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
500
|
-
max_metric_calls=None, # budget: the metric-call ceiling for
|
|
500
|
+
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
501
501
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
502
502
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
503
|
-
|
|
504
|
-
patience=2, # optional: stop after this many steps without improvement
|
|
505
|
-
seed=0, # optional: the starting seed, advanced each step
|
|
503
|
+
seed=0, # optional: the search's random seed
|
|
506
504
|
poll_interval=3.0, # optional: seconds between status checks
|
|
507
|
-
timeout=600.0, # optional: seconds to wait for
|
|
505
|
+
timeout=600.0, # optional: seconds to wait for the run
|
|
508
506
|
)
|
|
509
507
|
```
|
|
510
508
|
|
|
@@ -516,6 +514,21 @@ budget is missing.
|
|
|
516
514
|
initiation with a 4xx, such as a 409 for missing data or a metric mismatch. It
|
|
517
515
|
raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
|
|
518
516
|
|
|
517
|
+
The result's `optimization_run_id` names the run that produced it.
|
|
518
|
+
`continue_optimization()` starts a new run from one of that run's candidates,
|
|
519
|
+
reusing its data, with a budget of its own:
|
|
520
|
+
|
|
521
|
+
```python
|
|
522
|
+
better = sdk.continue_optimization(best, max_metric_calls=120) # from the best candidate
|
|
523
|
+
|
|
524
|
+
for candidate in sdk.list_candidates(best.optimization_run_id): # read each one first
|
|
525
|
+
print(candidate["candidate_id"], candidate["aggregate_score"], candidate["instructions"])
|
|
526
|
+
other = sdk.continue_optimization(best, candidate="ca_...", auto="light")
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
530
|
+
`not_completed` or `unknown_candidate`.
|
|
531
|
+
|
|
519
532
|
## Command line
|
|
520
533
|
|
|
521
534
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -639,6 +652,11 @@ global config. Use it as a context manager or as a plain object.
|
|
|
639
652
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
640
653
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
641
654
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
655
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
656
|
+
`ca_` id, score, parent and instructions.
|
|
657
|
+
- `continue_optimization(run, candidate=None, ...)` runs a new optimization
|
|
658
|
+
from one candidate of a completed run, with that run's data and a new budget,
|
|
659
|
+
and returns its best `DeployedProgram`.
|
|
642
660
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
643
661
|
client's credentials. They flush the client's traces first.
|
|
644
662
|
- `close()` flushes the client's traces and closes the client. A closed
|
|
@@ -446,14 +446,12 @@ sdk.optimize_deployment(
|
|
|
446
446
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
447
447
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
448
448
|
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
449
|
-
max_metric_calls=None, # budget: the metric-call ceiling for
|
|
449
|
+
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
450
450
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
451
451
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
452
|
-
|
|
453
|
-
patience=2, # optional: stop after this many steps without improvement
|
|
454
|
-
seed=0, # optional: the starting seed, advanced each step
|
|
452
|
+
seed=0, # optional: the search's random seed
|
|
455
453
|
poll_interval=3.0, # optional: seconds between status checks
|
|
456
|
-
timeout=600.0, # optional: seconds to wait for
|
|
454
|
+
timeout=600.0, # optional: seconds to wait for the run
|
|
457
455
|
)
|
|
458
456
|
```
|
|
459
457
|
|
|
@@ -465,6 +463,21 @@ budget is missing.
|
|
|
465
463
|
initiation with a 4xx, such as a 409 for missing data or a metric mismatch. It
|
|
466
464
|
raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
|
|
467
465
|
|
|
466
|
+
The result's `optimization_run_id` names the run that produced it.
|
|
467
|
+
`continue_optimization()` starts a new run from one of that run's candidates,
|
|
468
|
+
reusing its data, with a budget of its own:
|
|
469
|
+
|
|
470
|
+
```python
|
|
471
|
+
better = sdk.continue_optimization(best, max_metric_calls=120) # from the best candidate
|
|
472
|
+
|
|
473
|
+
for candidate in sdk.list_candidates(best.optimization_run_id): # read each one first
|
|
474
|
+
print(candidate["candidate_id"], candidate["aggregate_score"], candidate["instructions"])
|
|
475
|
+
other = sdk.continue_optimization(best, candidate="ca_...", auto="light")
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
479
|
+
`not_completed` or `unknown_candidate`.
|
|
480
|
+
|
|
468
481
|
## Command line
|
|
469
482
|
|
|
470
483
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -588,6 +601,11 @@ global config. Use it as a context manager or as a plain object.
|
|
|
588
601
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
589
602
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
590
603
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
604
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
605
|
+
`ca_` id, score, parent and instructions.
|
|
606
|
+
- `continue_optimization(run, candidate=None, ...)` runs a new optimization
|
|
607
|
+
from one candidate of a completed run, with that run's data and a new budget,
|
|
608
|
+
and returns its best `DeployedProgram`.
|
|
591
609
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
592
610
|
client's credentials. They flush the client's traces first.
|
|
593
611
|
- `close()` flushes the client's traces and closes the client. A closed
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
from argparse import ArgumentParser, _SubParsersAction
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
8
9
|
from .. import api_client, deprecation, pagination
|
|
10
|
+
from . import top
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def _add_list_args(p: ArgumentParser) -> None:
|
|
@@ -88,6 +90,42 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
88
90
|
cancel.add_argument("id", help="Optimization run ID (op_...)")
|
|
89
91
|
cancel.set_defaults(func=handle_cancel)
|
|
90
92
|
|
|
93
|
+
cont = sub.add_parser(
|
|
94
|
+
"continue",
|
|
95
|
+
help="Run a new optimization from one candidate of a completed run. It reuses that run's data, models "
|
|
96
|
+
"and credentials, and takes a new budget",
|
|
97
|
+
)
|
|
98
|
+
cont.add_argument("id", help="Completed optimization run ID (op_...)")
|
|
99
|
+
cont.add_argument(
|
|
100
|
+
"--candidate",
|
|
101
|
+
metavar="CANDIDATE_ID",
|
|
102
|
+
help="The ca_ id of the candidate to start from, as `cmpnd optimizations candidates ID` lists them "
|
|
103
|
+
"(default: the run's best)",
|
|
104
|
+
)
|
|
105
|
+
# The budget flags are `cmpnd optimize`'s, and the SDK refuses a run with none or two,
|
|
106
|
+
# so both commands answer a missing budget the same way.
|
|
107
|
+
cont.add_argument(
|
|
108
|
+
"--max-metric-calls",
|
|
109
|
+
dest="max_metric_calls",
|
|
110
|
+
type=int,
|
|
111
|
+
default=None,
|
|
112
|
+
help="Budget for the search, as metric calls (one per rollout). Required unless --auto is given",
|
|
113
|
+
)
|
|
114
|
+
cont.add_argument(
|
|
115
|
+
"--auto",
|
|
116
|
+
choices=["light", "medium", "heavy"],
|
|
117
|
+
default=None,
|
|
118
|
+
help="Budget as a t-shirt size, sized from the program and valset (alternative to --max-metric-calls)",
|
|
119
|
+
)
|
|
120
|
+
cont.add_argument(
|
|
121
|
+
"--async",
|
|
122
|
+
dest="asynchronous",
|
|
123
|
+
action="store_true",
|
|
124
|
+
help="Return the queued run at once instead of waiting for it to finish",
|
|
125
|
+
)
|
|
126
|
+
cont.add_argument("--json", action="store_true", help="Emit the result summary as JSON")
|
|
127
|
+
cont.set_defaults(func=handle_continue)
|
|
128
|
+
|
|
91
129
|
delete = sub.add_parser("delete", help="Delete an optimization run and everything recorded under it")
|
|
92
130
|
delete.add_argument("id", help="Optimization run ID (op_...)")
|
|
93
131
|
delete.set_defaults(func=handle_delete)
|
|
@@ -124,8 +162,11 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
124
162
|
iters.add_argument("id", help="Optimization run ID (UUID)")
|
|
125
163
|
iters.set_defaults(func=handle_iterations)
|
|
126
164
|
|
|
127
|
-
cands = sub.add_parser(
|
|
128
|
-
|
|
165
|
+
cands = sub.add_parser(
|
|
166
|
+
"candidates",
|
|
167
|
+
help="List a run's candidates: each one's ca_ id, score and parent, to pick one to continue from",
|
|
168
|
+
)
|
|
169
|
+
cands.add_argument("id", help="Optimization run ID (op_...)")
|
|
129
170
|
cands.add_argument(
|
|
130
171
|
"--full",
|
|
131
172
|
action="store_true",
|
|
@@ -213,6 +254,80 @@ def handle_cancel(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
213
254
|
return client.post(f"/api/v1/optimizations/{args.id}/cancel")
|
|
214
255
|
|
|
215
256
|
|
|
257
|
+
def handle_continue(client: api_client.ApiClient, args: Any) -> Any:
|
|
258
|
+
"""Run a new optimization from one candidate of a completed run, as `cmpnd optimize` runs one.
|
|
259
|
+
|
|
260
|
+
The new run reuses the completed run's data and configuration and takes a new budget.
|
|
261
|
+
The command names the candidate it starts from, waits for the run, and prints the
|
|
262
|
+
best program as `cmpnd optimize` does. `--async` returns the queued run instead.
|
|
263
|
+
"""
|
|
264
|
+
from ... import optimization
|
|
265
|
+
|
|
266
|
+
cfg = top.sdk_config(client)
|
|
267
|
+
try:
|
|
268
|
+
started = optimization.start_continuation(
|
|
269
|
+
args.id,
|
|
270
|
+
cfg=cfg,
|
|
271
|
+
candidate=args.candidate,
|
|
272
|
+
max_metric_calls=args.max_metric_calls,
|
|
273
|
+
auto=args.auto,
|
|
274
|
+
)
|
|
275
|
+
except (optimization.OptimizeError, ValueError) as exc:
|
|
276
|
+
raise api_client.CliError(str(exc)) from exc
|
|
277
|
+
if args.asynchronous:
|
|
278
|
+
return started
|
|
279
|
+
|
|
280
|
+
texts = _instruction_texts(started.get("candidate_instructions"))
|
|
281
|
+
score = started.get("candidate_score")
|
|
282
|
+
print(
|
|
283
|
+
top._c(
|
|
284
|
+
f"continuing {args.id} from {started.get('continued_from_candidate_id')} "
|
|
285
|
+
f"(score {score:.3f}): {_first_line(texts)}"
|
|
286
|
+
if isinstance(score, (int, float))
|
|
287
|
+
else f"continuing {args.id} from {started.get('continued_from_candidate_id')}",
|
|
288
|
+
"dim",
|
|
289
|
+
),
|
|
290
|
+
file=sys.stderr,
|
|
291
|
+
)
|
|
292
|
+
print(top._c(f"optimizing with {started.get('optimizer')}…", "dim"), file=sys.stderr)
|
|
293
|
+
try:
|
|
294
|
+
result = optimization.wait_for_continuation(started, cfg=cfg)
|
|
295
|
+
except (optimization.OptimizeError, optimization.OptimizeFailed) as exc:
|
|
296
|
+
raise api_client.CliError(str(exc)) from exc
|
|
297
|
+
top.print_optimize_result(
|
|
298
|
+
result,
|
|
299
|
+
as_json=args.json,
|
|
300
|
+
extra={
|
|
301
|
+
"optimization_id": started.get("optimization_id"),
|
|
302
|
+
"continued_from_run_id": started.get("continued_from_run_id"),
|
|
303
|
+
"continued_from_candidate_id": started.get("continued_from_candidate_id"),
|
|
304
|
+
},
|
|
305
|
+
)
|
|
306
|
+
return None
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _instruction_texts(instructions: Any) -> list[tuple[str, str]]:
|
|
310
|
+
"""A candidate's instructions as (component, text) pairs, in the order serve sent them."""
|
|
311
|
+
if not isinstance(instructions, dict):
|
|
312
|
+
return []
|
|
313
|
+
return [(str(name), text if isinstance(text, str) else str(text)) for name, text in instructions.items()]
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _first_line(texts: list[tuple[str, str]], width: int = 72) -> str:
|
|
317
|
+
"""The first line of the first component's text, naming the component when there are several."""
|
|
318
|
+
if not texts:
|
|
319
|
+
return "-"
|
|
320
|
+
name, text = texts[0]
|
|
321
|
+
line = next((ln.strip() for ln in text.splitlines() if ln.strip()), "")
|
|
322
|
+
if len(texts) > 1:
|
|
323
|
+
line = f"{name}: {line}"
|
|
324
|
+
if len(line) > width:
|
|
325
|
+
line = line[: width - 1] + "…"
|
|
326
|
+
if len(texts) > 1:
|
|
327
|
+
line += f" (+{len(texts) - 1} more)"
|
|
328
|
+
return line
|
|
329
|
+
|
|
330
|
+
|
|
216
331
|
def handle_delete(client: api_client.ApiClient, args: Any) -> Any:
|
|
217
332
|
# 204 No Content → delete() returns None; synthesize a confirmation.
|
|
218
333
|
client.delete(f"/api/v1/optimizations/{args.id}")
|
|
@@ -1028,7 +1028,7 @@ def _optimize_credentials(
|
|
|
1028
1028
|
``cmpnd.HostedLM`` when ``--reflection-credential`` names its credential) and the
|
|
1029
1029
|
credential per binding. :class:`_CredentialLookup` turns each name into a
|
|
1030
1030
|
``cmpnd.Credential``, so a mistyped one fails before the import and the deploy a run
|
|
1031
|
-
makes ahead of
|
|
1031
|
+
makes ahead of the optimization.
|
|
1032
1032
|
"""
|
|
1033
1033
|
from ...lm_configuration import HostedLM
|
|
1034
1034
|
|
|
@@ -1133,29 +1133,30 @@ def cmd_optimize(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
1133
1133
|
lm_credentials=lm_credentials,
|
|
1134
1134
|
max_metric_calls=getattr(args, "max_metric_calls", None),
|
|
1135
1135
|
auto=getattr(args, "auto", None),
|
|
1136
|
-
max_steps=getattr(args, "max_steps", 10),
|
|
1137
|
-
patience=getattr(args, "patience", 2),
|
|
1138
1136
|
seed=getattr(args, "seed", 0),
|
|
1139
1137
|
)
|
|
1140
1138
|
except (optimization.OptimizeError, optimization.OptimizeFailed, ValueError) as exc:
|
|
1141
1139
|
raise api_client.CliError(str(exc))
|
|
1142
1140
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1141
|
+
print_optimize_result(result, as_json=getattr(args, "json", False))
|
|
1142
|
+
return result
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
def print_optimize_result(result: Any, *, as_json: bool, extra: dict[str, Any] | None = None) -> None:
|
|
1146
|
+
"""Print a finished optimization's best program, as every command that runs one does.
|
|
1147
|
+
|
|
1148
|
+
The best deployment's id goes to stdout and its score to stderr, so a script can
|
|
1149
|
+
capture the id alone. ``--json`` prints both, and ``extra`` adds fields a command
|
|
1150
|
+
knows about the run.
|
|
1151
|
+
"""
|
|
1152
|
+
if as_json:
|
|
1153
|
+
summary = {"best_deployment_id": result.deployment_id, "best_score": result.score}
|
|
1154
|
+
summary.update(extra or {})
|
|
1155
|
+
print(json.dumps(summary, indent=2, default=str))
|
|
1154
1156
|
else:
|
|
1155
1157
|
print(result.deployment_id)
|
|
1156
1158
|
score = "n/a" if result.score is None else f"{result.score}"
|
|
1157
1159
|
print(_c(f"best score: {score}", "dim"), file=sys.stderr)
|
|
1158
|
-
return result
|
|
1159
1160
|
|
|
1160
1161
|
|
|
1161
1162
|
def cmd_run(client: api_client.ApiClient, args: Any) -> None:
|
|
@@ -1563,7 +1564,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1563
1564
|
dest="max_metric_calls",
|
|
1564
1565
|
type=int,
|
|
1565
1566
|
default=None,
|
|
1566
|
-
help="Budget for
|
|
1567
|
+
help="Budget for the search, as metric calls (one per rollout). Required unless --auto is given",
|
|
1567
1568
|
)
|
|
1568
1569
|
opt.add_argument(
|
|
1569
1570
|
"--auto",
|
|
@@ -1571,15 +1572,6 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1571
1572
|
default=None,
|
|
1572
1573
|
help="Budget as a t-shirt size, sized from the program and valset (alternative to --max-metric-calls)",
|
|
1573
1574
|
)
|
|
1574
|
-
opt.add_argument(
|
|
1575
|
-
"--max-steps",
|
|
1576
|
-
dest="max_steps",
|
|
1577
|
-
type=int,
|
|
1578
|
-
default=10,
|
|
1579
|
-
help="How many times to re-optimize the winner, each step a fresh search "
|
|
1580
|
-
"with an advanced seed (default 10). Bounds the LOOP, not one search",
|
|
1581
|
-
)
|
|
1582
|
-
opt.add_argument("--patience", type=int, default=2, help="Stop after this many consecutive non-improving steps")
|
|
1583
|
-
opt.add_argument("--seed", type=int, default=0, help="Starting seed; advanced each step")
|
|
1575
|
+
opt.add_argument("--seed", type=int, default=0, help="The search's random seed (default 0)")
|
|
1584
1576
|
opt.add_argument("--json", action="store_true", help="Emit the result summary as JSON")
|
|
1585
1577
|
opt.set_defaults(func=_handler("optimize"))
|
|
@@ -537,8 +537,6 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
|
|
|
537
537
|
reflection_model: str | None = None,
|
|
538
538
|
source_root: str | None = None,
|
|
539
539
|
include: list[str] | None = None,
|
|
540
|
-
max_steps: int = 10,
|
|
541
|
-
patience: int = 2,
|
|
542
540
|
seed: int = 0,
|
|
543
541
|
# Deprecated program id input: refused, and goes when the deprecated inputs are stripped out.
|
|
544
542
|
program_id: str | None = None,
|
|
@@ -568,8 +566,6 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
|
|
|
568
566
|
reflection_model=reflection_model,
|
|
569
567
|
source_root=source_root,
|
|
570
568
|
include=list(include or []),
|
|
571
|
-
max_steps=max_steps,
|
|
572
|
-
patience=patience,
|
|
573
569
|
seed=seed,
|
|
574
570
|
),
|
|
575
571
|
)
|
|
@@ -154,6 +154,7 @@ DOMAIN_VERBS: dict[str, str] = {
|
|
|
154
154
|
"wait": "polls one accepted run until it settles or the local budget expires",
|
|
155
155
|
"cancel": "settles an open run as cancelled and keeps its record; delete would read as removing the run",
|
|
156
156
|
"follow": "tails a record until it settles — a list over time rather than a snapshot",
|
|
157
|
+
"continue": "starts a run from one candidate of a completed run; create would hide that it inherits its data",
|
|
157
158
|
"select": "marks one candidate as the program's chosen version",
|
|
158
159
|
"refresh": "re-reads a record from the system of record it mirrors; nothing the caller supplies is written",
|
|
159
160
|
"allow": "grants permission to call a tool — a person's decision, never inferred from what code names",
|
|
@@ -507,17 +507,14 @@ class Client:
|
|
|
507
507
|
max_metric_calls: int | None = None,
|
|
508
508
|
auto: str | None = None,
|
|
509
509
|
may_author_code: bool | None = None,
|
|
510
|
-
max_steps: int = 10,
|
|
511
|
-
patience: int = 2,
|
|
512
510
|
seed: int = 0,
|
|
513
511
|
poll_interval: float = 3.0,
|
|
514
512
|
timeout: float = 600.0,
|
|
515
513
|
) -> Any:
|
|
516
514
|
"""Optimize a deployment on the platform, on this client's account, and return the best deployment.
|
|
517
515
|
|
|
518
|
-
Runs
|
|
519
|
-
|
|
520
|
-
seed until improvement plateaus. Deploy the program first with
|
|
516
|
+
Runs one optimization: upload the optimization bundle, wait for the run to
|
|
517
|
+
settle, and return its result deployment. Deploy the program first with
|
|
521
518
|
``deploy_program``. The optimization belongs to the deployment's program, and
|
|
522
519
|
the program's model comes from the deployment.
|
|
523
520
|
|
|
@@ -676,28 +673,23 @@ class Client:
|
|
|
676
673
|
optimizes every ordinary predictor and leaves each ``dspy.Flex`` at
|
|
677
674
|
the source you deployed. A program with no ``dspy.Flex`` in it is
|
|
678
675
|
unaffected either way.
|
|
679
|
-
|
|
680
|
-
``optimize`` call with an advanced seed (default 10). Distinct from
|
|
681
|
-
the budget above, which bounds ONE step's search: total spend is
|
|
682
|
-
roughly the budget times the steps actually taken.
|
|
683
|
-
patience: Stop after this many consecutive non-improving steps (default 2).
|
|
684
|
-
seed: Starting seed; advanced by 1 each step (default 0).
|
|
676
|
+
seed: The search's random seed (default 0).
|
|
685
677
|
poll_interval: Seconds between status polls (default 3.0).
|
|
686
|
-
timeout:
|
|
687
|
-
|
|
688
|
-
|
|
678
|
+
timeout: Polling timeout in seconds (default 600). Also the outer bound
|
|
679
|
+
on riding through transient answers: the run's backoff waits are
|
|
680
|
+
clipped by it rather than extending the wait past it.
|
|
689
681
|
|
|
690
682
|
Returns:
|
|
691
|
-
The
|
|
692
|
-
``.score`` is the best score
|
|
683
|
+
The run's result ``cmpnd.DeployedProgram``. Run it with ``run_deployment``.
|
|
684
|
+
Its ``.score`` is the run's best score (``None`` if the server returned no
|
|
693
685
|
scores).
|
|
694
686
|
|
|
695
687
|
Raises:
|
|
696
688
|
ValueError: A retired optimizer, an unknown one, a metric that is not a
|
|
697
689
|
5-arg feedback metric (or whose signature cannot be introspected), or a
|
|
698
690
|
proposer the sandbox could not call or whose source cannot be recovered.
|
|
699
|
-
OptimizeError: A 4xx initiating
|
|
700
|
-
OptimizeFailed:
|
|
691
|
+
OptimizeError: A 4xx initiating the run (e.g. 409 mismatch).
|
|
692
|
+
OptimizeFailed: The run transitioned to ``status="failed"``.
|
|
701
693
|
TypeError: A string for ``credential``. Look a credential up with
|
|
702
694
|
``cmpnd.credentials.get``.
|
|
703
695
|
"""
|
|
@@ -719,13 +711,71 @@ class Client:
|
|
|
719
711
|
max_metric_calls=max_metric_calls,
|
|
720
712
|
auto=auto,
|
|
721
713
|
may_author_code=may_author_code,
|
|
722
|
-
max_steps=max_steps,
|
|
723
|
-
patience=patience,
|
|
724
714
|
seed=seed,
|
|
725
715
|
poll_interval=poll_interval,
|
|
726
716
|
timeout=timeout,
|
|
727
717
|
)
|
|
728
718
|
|
|
719
|
+
def continue_optimization(
|
|
720
|
+
self,
|
|
721
|
+
run: Any,
|
|
722
|
+
*,
|
|
723
|
+
candidate: str | None = None,
|
|
724
|
+
max_metric_calls: int | None = None,
|
|
725
|
+
auto: str | None = None,
|
|
726
|
+
poll_interval: float = 3.0,
|
|
727
|
+
timeout: float = 600.0,
|
|
728
|
+
) -> Any:
|
|
729
|
+
"""Run a new optimization from one candidate of a completed one, and return its best program.
|
|
730
|
+
|
|
731
|
+
The new run is a fresh search that starts from the chosen candidate, with its own
|
|
732
|
+
budget. It reuses the completed run's training and validation data and its
|
|
733
|
+
configuration, so nothing is uploaded::
|
|
734
|
+
|
|
735
|
+
best = client.optimize_deployment(deployed, ..., max_metric_calls=120)
|
|
736
|
+
better = client.continue_optimization(best, max_metric_calls=120)
|
|
737
|
+
|
|
738
|
+
Args:
|
|
739
|
+
run: The completed run's ``op_`` id, or the ``DeployedProgram`` an
|
|
740
|
+
optimization returned.
|
|
741
|
+
candidate: The ``ca_`` id of the candidate to start from, as
|
|
742
|
+
``list_candidates`` and ``cmpnd optimizations candidates`` list it. The
|
|
743
|
+
default is the run's best.
|
|
744
|
+
max_metric_calls: The budget as a ceiling on metric calls. Pass this or
|
|
745
|
+
``auto``, exactly one.
|
|
746
|
+
auto: The budget as ``"light"``, ``"medium"`` or ``"heavy"``.
|
|
747
|
+
poll_interval: Seconds between status polls (default 3.0).
|
|
748
|
+
timeout: Polling timeout in seconds (default 600).
|
|
749
|
+
|
|
750
|
+
Returns:
|
|
751
|
+
The new run's best program, a ``cmpnd.DeployedProgram``, as
|
|
752
|
+
``optimize_deployment`` returns.
|
|
753
|
+
|
|
754
|
+
Raises:
|
|
755
|
+
ValueError: No budget or two budgets, or a ``DeployedProgram`` that no
|
|
756
|
+
optimization produced.
|
|
757
|
+
OptimizeError: The platform refused the continuation. Its ``error_code``
|
|
758
|
+
says why, for example ``not_completed`` or ``unknown_candidate``.
|
|
759
|
+
OptimizeFailed: The new run transitioned to ``status="failed"``.
|
|
760
|
+
"""
|
|
761
|
+
self._check_active()
|
|
762
|
+
from . import execution, optimization
|
|
763
|
+
|
|
764
|
+
run_id = run.optimization_run_id if isinstance(run, execution.DeployedProgram) else run
|
|
765
|
+
if not run_id:
|
|
766
|
+
raise ValueError(
|
|
767
|
+
f"deployment {run} is not the result of an optimization this client ran; pass the run's op_ id"
|
|
768
|
+
)
|
|
769
|
+
return optimization.continue_optimization(
|
|
770
|
+
run_id,
|
|
771
|
+
cfg=self._config,
|
|
772
|
+
candidate=candidate,
|
|
773
|
+
max_metric_calls=max_metric_calls,
|
|
774
|
+
auto=auto,
|
|
775
|
+
poll_interval=poll_interval,
|
|
776
|
+
timeout=timeout,
|
|
777
|
+
)
|
|
778
|
+
|
|
729
779
|
# -- data surface (flat verb-object over the client's credentials) -----
|
|
730
780
|
#
|
|
731
781
|
# Flat methods (create_valset_entry, list_assessments, get_trace, …), so the
|
|
@@ -747,6 +797,22 @@ class Client:
|
|
|
747
797
|
_exporter_pool.flush(self._config)
|
|
748
798
|
return programs.program_id_for(_http.ApiClient(self._config.api_key, self._config.endpoint), program)
|
|
749
799
|
|
|
800
|
+
def list_candidates(self, run_id: str) -> list[dict[str, Any]]:
|
|
801
|
+
"""The candidates of an optimization run, to choose one to continue from.
|
|
802
|
+
|
|
803
|
+
Each carries its ``candidate_id`` (``ca_…``), ``aggregate_score``,
|
|
804
|
+
``parent_candidate_id`` and ``instructions``, so a caller picks by what a
|
|
805
|
+
candidate is::
|
|
806
|
+
|
|
807
|
+
candidates = client.list_candidates("op_…")
|
|
808
|
+
chosen = max(candidates, key=lambda c: c["aggregate_score"])
|
|
809
|
+
client.continue_optimization("op_…", candidate=chosen["candidate_id"], max_metric_calls=120)
|
|
810
|
+
"""
|
|
811
|
+
self._check_active()
|
|
812
|
+
from . import optimization
|
|
813
|
+
|
|
814
|
+
return optimization.list_candidates(run_id, cfg=self._config)
|
|
815
|
+
|
|
750
816
|
def get_deployment_signature(self, deployment_id: str) -> DeploymentSignatureResponse:
|
|
751
817
|
"""Fetch one deployment's persisted artifact metadata."""
|
|
752
818
|
self._check_active()
|
|
@@ -114,8 +114,12 @@ class DeployedProgram:
|
|
|
114
114
|
endpoint: str | None = None,
|
|
115
115
|
score: float | None = None,
|
|
116
116
|
deployment_signature: DeploymentSignatureResponse | None = None,
|
|
117
|
+
optimization_run_id: str | None = None,
|
|
117
118
|
) -> None:
|
|
118
119
|
self.deployment_id = deployment_id
|
|
120
|
+
#: The optimization run that produced this program, when it is a run's result.
|
|
121
|
+
#: ``cmpnd.Client.continue_optimization`` takes such a program in place of a run id.
|
|
122
|
+
self.optimization_run_id = optimization_run_id
|
|
119
123
|
self.deployment_signature = deployment_signature
|
|
120
124
|
self.artifact_metadata: DeploymentArtifactMetadata | None = None
|
|
121
125
|
self.metadata_unavailable_reason: str | None = None
|