cmpnd 0.64.0__tar.gz → 0.66.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.66.0}/PKG-INFO +34 -6
- {cmpnd-0.64.0 → cmpnd-0.66.0}/README.md +33 -5
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/optimizations.py +142 -2
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/top.py +18 -26
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/shell.py +0 -4
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/verbs.py +1 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/client.py +109 -20
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/execution.py +4 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimization.py +210 -116
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/cli.md +43 -3
- {cmpnd-0.64.0 → cmpnd-0.66.0}/pyproject.toml +1 -1
- cmpnd-0.66.0/tests/e2e/continuation_task.py +72 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_deploy_pandas.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_authored_metric.py +0 -2
- cmpnd-0.66.0/tests/e2e/test_optimize_continuation.py +150 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_custom_proposer.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_failures.py +0 -2
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_loop.py +0 -3
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/hosted_optimize_probe.py +0 -1
- cmpnd-0.66.0/tests/stress/test_optimize_continuation.py +170 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_optimize_loop.py +1 -2
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_optimize_loop_wasm.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_optimize_stress.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored_binding_credentials.py +3 -3
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored_metric_contract.py +5 -5
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored_named_models.py +0 -2
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored_optimize.py +3 -3
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_optimizations.py +140 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_top.py +4 -3
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_credential_selection.py +6 -6
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deploy_program_id.py +11 -14
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_lm_configuration.py +1 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize.py +307 -81
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_budget.py +3 -4
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_proposer.py +0 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_program_names_in_deploy.py +3 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/uv.lock +1 -1
- {cmpnd-0.64.0 → cmpnd-0.66.0}/.gitignore +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/AGENTS.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/CLAUDE.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/context.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/models.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/client.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/docs/sdk-instrumentation.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/README.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/release-stress.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/drain.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/_provider.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/_reliability.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/_result.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/mint_bedrock_token.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_bedrock_converse.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_deploy_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_multi_client_stress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_optimize_client_committee.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_provider_roles.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_real_provider_twins.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_reliability.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_reliability_classify.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_rlm_wasm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/stress/test_trace_search.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_client.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_context.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_eval.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_execute.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_integration.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_models.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_release_stress_script.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_retry.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.64.0 → cmpnd-0.66.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.66.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,30 @@ 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
|
+
`model=` runs the candidate on another student model, and `credential=` names
|
|
530
|
+
the credential that model spends. A loop over models is a model sweep:
|
|
531
|
+
|
|
532
|
+
```python
|
|
533
|
+
for model in ["openai/gpt-4o-mini", "openai/gpt-4.1-nano"]:
|
|
534
|
+
swept = sdk.continue_optimization(best, model=model, auto="light")
|
|
535
|
+
print(model, swept.score)
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
539
|
+
`not_completed`, `unknown_candidate` or `no_credential`.
|
|
540
|
+
|
|
519
541
|
## Command line
|
|
520
542
|
|
|
521
543
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -639,6 +661,12 @@ global config. Use it as a context manager or as a plain object.
|
|
|
639
661
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
640
662
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
641
663
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
664
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
665
|
+
`ca_` id, score, parent and instructions.
|
|
666
|
+
- `continue_optimization(run, candidate=None, model=None, credential=None, ...)`
|
|
667
|
+
runs a new optimization from one candidate of a completed run, with that
|
|
668
|
+
run's data and a new budget, optionally on another student model, and returns
|
|
669
|
+
its best `DeployedProgram`.
|
|
642
670
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
643
671
|
client's credentials. They flush the client's traces first.
|
|
644
672
|
- `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,30 @@ 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
|
+
`model=` runs the candidate on another student model, and `credential=` names
|
|
479
|
+
the credential that model spends. A loop over models is a model sweep:
|
|
480
|
+
|
|
481
|
+
```python
|
|
482
|
+
for model in ["openai/gpt-4o-mini", "openai/gpt-4.1-nano"]:
|
|
483
|
+
swept = sdk.continue_optimization(best, model=model, auto="light")
|
|
484
|
+
print(model, swept.score)
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
488
|
+
`not_completed`, `unknown_candidate` or `no_credential`.
|
|
489
|
+
|
|
468
490
|
## Command line
|
|
469
491
|
|
|
470
492
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -588,6 +610,12 @@ global config. Use it as a context manager or as a plain object.
|
|
|
588
610
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
589
611
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
590
612
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
613
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
614
|
+
`ca_` id, score, parent and instructions.
|
|
615
|
+
- `continue_optimization(run, candidate=None, model=None, credential=None, ...)`
|
|
616
|
+
runs a new optimization from one candidate of a completed run, with that
|
|
617
|
+
run's data and a new budget, optionally on another student model, and returns
|
|
618
|
+
its best `DeployedProgram`.
|
|
591
619
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
592
620
|
client's credentials. They flush the client's traces first.
|
|
593
621
|
- `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,55 @@ 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. --model runs the candidate on another student model",
|
|
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
|
+
cont.add_argument(
|
|
106
|
+
"--model",
|
|
107
|
+
default=None,
|
|
108
|
+
help="The student model the new run spends, as a deploy records it, for example openai/gpt-4o-mini "
|
|
109
|
+
"(default: the completed run's). Only the program's own model changes",
|
|
110
|
+
)
|
|
111
|
+
cont.add_argument(
|
|
112
|
+
"--credential",
|
|
113
|
+
metavar="NAME",
|
|
114
|
+
default=None,
|
|
115
|
+
help="The provider credential the student model spends (default: the completed run's). "
|
|
116
|
+
"`cmpnd credentials list` shows the names",
|
|
117
|
+
)
|
|
118
|
+
# The budget flags are `cmpnd optimize`'s, and the SDK refuses a run with none or two,
|
|
119
|
+
# so both commands answer a missing budget the same way.
|
|
120
|
+
cont.add_argument(
|
|
121
|
+
"--max-metric-calls",
|
|
122
|
+
dest="max_metric_calls",
|
|
123
|
+
type=int,
|
|
124
|
+
default=None,
|
|
125
|
+
help="Budget for the search, as metric calls (one per rollout). Required unless --auto is given",
|
|
126
|
+
)
|
|
127
|
+
cont.add_argument(
|
|
128
|
+
"--auto",
|
|
129
|
+
choices=["light", "medium", "heavy"],
|
|
130
|
+
default=None,
|
|
131
|
+
help="Budget as a t-shirt size, sized from the program and valset (alternative to --max-metric-calls)",
|
|
132
|
+
)
|
|
133
|
+
cont.add_argument(
|
|
134
|
+
"--async",
|
|
135
|
+
dest="asynchronous",
|
|
136
|
+
action="store_true",
|
|
137
|
+
help="Return the queued run at once instead of waiting for it to finish",
|
|
138
|
+
)
|
|
139
|
+
cont.add_argument("--json", action="store_true", help="Emit the result summary as JSON")
|
|
140
|
+
cont.set_defaults(func=handle_continue)
|
|
141
|
+
|
|
91
142
|
delete = sub.add_parser("delete", help="Delete an optimization run and everything recorded under it")
|
|
92
143
|
delete.add_argument("id", help="Optimization run ID (op_...)")
|
|
93
144
|
delete.set_defaults(func=handle_delete)
|
|
@@ -124,8 +175,11 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
124
175
|
iters.add_argument("id", help="Optimization run ID (UUID)")
|
|
125
176
|
iters.set_defaults(func=handle_iterations)
|
|
126
177
|
|
|
127
|
-
cands = sub.add_parser(
|
|
128
|
-
|
|
178
|
+
cands = sub.add_parser(
|
|
179
|
+
"candidates",
|
|
180
|
+
help="List a run's candidates: each one's ca_ id, score and parent, to pick one to continue from",
|
|
181
|
+
)
|
|
182
|
+
cands.add_argument("id", help="Optimization run ID (op_...)")
|
|
129
183
|
cands.add_argument(
|
|
130
184
|
"--full",
|
|
131
185
|
action="store_true",
|
|
@@ -213,6 +267,92 @@ def handle_cancel(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
213
267
|
return client.post(f"/api/v1/optimizations/{args.id}/cancel")
|
|
214
268
|
|
|
215
269
|
|
|
270
|
+
def handle_continue(client: api_client.ApiClient, args: Any) -> Any:
|
|
271
|
+
"""Run a new optimization from one candidate of a completed run, as `cmpnd optimize` runs one.
|
|
272
|
+
|
|
273
|
+
The new run reuses the completed run's data and configuration and takes a new budget.
|
|
274
|
+
`--model` and `--credential` run the candidate on another student model. The command
|
|
275
|
+
names the candidate it starts from, waits for the run, and prints the best program as
|
|
276
|
+
`cmpnd optimize` does. `--async` returns the queued run instead.
|
|
277
|
+
"""
|
|
278
|
+
from ... import optimization
|
|
279
|
+
|
|
280
|
+
credential_name = args.credential
|
|
281
|
+
if credential_name is not None:
|
|
282
|
+
credential_name = top._CredentialLookup(client)(f"--credential {credential_name}", credential_name).name
|
|
283
|
+
cfg = top.sdk_config(client)
|
|
284
|
+
try:
|
|
285
|
+
started = optimization.start_continuation(
|
|
286
|
+
args.id,
|
|
287
|
+
cfg=cfg,
|
|
288
|
+
candidate=args.candidate,
|
|
289
|
+
model=args.model,
|
|
290
|
+
credential_name=credential_name,
|
|
291
|
+
max_metric_calls=args.max_metric_calls,
|
|
292
|
+
auto=args.auto,
|
|
293
|
+
)
|
|
294
|
+
except (optimization.OptimizeError, ValueError) as exc:
|
|
295
|
+
raise api_client.CliError(str(exc)) from exc
|
|
296
|
+
if args.asynchronous:
|
|
297
|
+
return started
|
|
298
|
+
|
|
299
|
+
texts = _instruction_texts(started.get("candidate_instructions"))
|
|
300
|
+
score = started.get("candidate_score")
|
|
301
|
+
print(
|
|
302
|
+
top._c(
|
|
303
|
+
f"continuing {args.id} from {started.get('continued_from_candidate_id')} "
|
|
304
|
+
f"(score {score:.3f}): {_first_line(texts)}"
|
|
305
|
+
if isinstance(score, (int, float))
|
|
306
|
+
else f"continuing {args.id} from {started.get('continued_from_candidate_id')}",
|
|
307
|
+
"dim",
|
|
308
|
+
),
|
|
309
|
+
file=sys.stderr,
|
|
310
|
+
)
|
|
311
|
+
if args.model is not None or args.credential is not None:
|
|
312
|
+
print(
|
|
313
|
+
top._c(f"on {started.get('model')} with the credential {started.get('credential_name')}", "dim"),
|
|
314
|
+
file=sys.stderr,
|
|
315
|
+
)
|
|
316
|
+
print(top._c(f"optimizing with {started.get('optimizer')}…", "dim"), file=sys.stderr)
|
|
317
|
+
try:
|
|
318
|
+
result = optimization.wait_for_continuation(started, cfg=cfg)
|
|
319
|
+
except (optimization.OptimizeError, optimization.OptimizeFailed) as exc:
|
|
320
|
+
raise api_client.CliError(str(exc)) from exc
|
|
321
|
+
top.print_optimize_result(
|
|
322
|
+
result,
|
|
323
|
+
as_json=args.json,
|
|
324
|
+
extra={
|
|
325
|
+
"optimization_id": started.get("optimization_id"),
|
|
326
|
+
"continued_from_run_id": started.get("continued_from_run_id"),
|
|
327
|
+
"continued_from_candidate_id": started.get("continued_from_candidate_id"),
|
|
328
|
+
**{key: started[key] for key in ("model", "credential_name") if key in started},
|
|
329
|
+
},
|
|
330
|
+
)
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _instruction_texts(instructions: Any) -> list[tuple[str, str]]:
|
|
335
|
+
"""A candidate's instructions as (component, text) pairs, in the order serve sent them."""
|
|
336
|
+
if not isinstance(instructions, dict):
|
|
337
|
+
return []
|
|
338
|
+
return [(str(name), text if isinstance(text, str) else str(text)) for name, text in instructions.items()]
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _first_line(texts: list[tuple[str, str]], width: int = 72) -> str:
|
|
342
|
+
"""The first line of the first component's text, naming the component when there are several."""
|
|
343
|
+
if not texts:
|
|
344
|
+
return "-"
|
|
345
|
+
name, text = texts[0]
|
|
346
|
+
line = next((ln.strip() for ln in text.splitlines() if ln.strip()), "")
|
|
347
|
+
if len(texts) > 1:
|
|
348
|
+
line = f"{name}: {line}"
|
|
349
|
+
if len(line) > width:
|
|
350
|
+
line = line[: width - 1] + "…"
|
|
351
|
+
if len(texts) > 1:
|
|
352
|
+
line += f" (+{len(texts) - 1} more)"
|
|
353
|
+
return line
|
|
354
|
+
|
|
355
|
+
|
|
216
356
|
def handle_delete(client: api_client.ApiClient, args: Any) -> Any:
|
|
217
357
|
# 204 No Content → delete() returns None; synthesize a confirmation.
|
|
218
358
|
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,94 @@ 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
|
+
model: str | None = None,
|
|
725
|
+
credential: credentials.Credential | None = None,
|
|
726
|
+
max_metric_calls: int | None = None,
|
|
727
|
+
auto: str | None = None,
|
|
728
|
+
poll_interval: float = 3.0,
|
|
729
|
+
timeout: float = 600.0,
|
|
730
|
+
) -> Any:
|
|
731
|
+
"""Run a new optimization from one candidate of a completed one, and return its best program.
|
|
732
|
+
|
|
733
|
+
The new run is a fresh search that starts from the chosen candidate, with its own
|
|
734
|
+
budget. It reuses the completed run's training and validation data and its
|
|
735
|
+
configuration, so nothing is uploaded::
|
|
736
|
+
|
|
737
|
+
best = client.optimize_deployment(deployed, ..., max_metric_calls=120)
|
|
738
|
+
better = client.continue_optimization(best, max_metric_calls=120)
|
|
739
|
+
|
|
740
|
+
With ``model``, the new run is a model sweep: the candidate runs and optimizes on
|
|
741
|
+
that student model instead of the completed run's. A loop over models compares
|
|
742
|
+
them on one task::
|
|
743
|
+
|
|
744
|
+
for model in ["openai/gpt-4o-mini", "openai/gpt-4.1-nano"]:
|
|
745
|
+
swept = client.continue_optimization(best, model=model, auto="light")
|
|
746
|
+
print(model, swept.score)
|
|
747
|
+
|
|
748
|
+
Args:
|
|
749
|
+
run: The completed run's ``op_`` id, or the ``DeployedProgram`` an
|
|
750
|
+
optimization returned.
|
|
751
|
+
candidate: The ``ca_`` id of the candidate to start from, as
|
|
752
|
+
``list_candidates`` and ``cmpnd optimizations candidates`` list it. The
|
|
753
|
+
default is the run's best.
|
|
754
|
+
model: The student model the new run spends, as a deploy records it, for
|
|
755
|
+
example ``"openai/gpt-4o-mini"``. The default is the completed run's.
|
|
756
|
+
Only the program's own model changes: a predictor with its own LM, the
|
|
757
|
+
run's ``lms`` and the reflection model stay as the completed run had
|
|
758
|
+
them.
|
|
759
|
+
credential: The credential the student model spends, from
|
|
760
|
+
``cmpnd.credentials.get(NAME)``. The default is the completed run's.
|
|
761
|
+
max_metric_calls: The budget as a ceiling on metric calls. Pass this or
|
|
762
|
+
``auto``, exactly one.
|
|
763
|
+
auto: The budget as ``"light"``, ``"medium"`` or ``"heavy"``.
|
|
764
|
+
poll_interval: Seconds between status polls (default 3.0).
|
|
765
|
+
timeout: Polling timeout in seconds (default 600).
|
|
766
|
+
|
|
767
|
+
Returns:
|
|
768
|
+
The new run's best program, a ``cmpnd.DeployedProgram``, as
|
|
769
|
+
``optimize_deployment`` returns.
|
|
770
|
+
|
|
771
|
+
Raises:
|
|
772
|
+
ValueError: No budget or two budgets, or a ``DeployedProgram`` that no
|
|
773
|
+
optimization produced.
|
|
774
|
+
TypeError: ``credential`` is a string. Look a credential up with
|
|
775
|
+
``cmpnd.credentials.get``.
|
|
776
|
+
OptimizeError: The platform refused the continuation. Its ``error_code``
|
|
777
|
+
says why, for example ``not_completed``, ``unknown_candidate`` or
|
|
778
|
+
``no_credential``.
|
|
779
|
+
OptimizeFailed: The new run transitioned to ``status="failed"``.
|
|
780
|
+
"""
|
|
781
|
+
self._check_active()
|
|
782
|
+
credential_name = credentials.name_of(credential, "cmpnd.Client.continue_optimization(credential=)")
|
|
783
|
+
from . import execution, optimization
|
|
784
|
+
|
|
785
|
+
run_id = run.optimization_run_id if isinstance(run, execution.DeployedProgram) else run
|
|
786
|
+
if not run_id:
|
|
787
|
+
raise ValueError(
|
|
788
|
+
f"deployment {run} is not the result of an optimization this client ran; pass the run's op_ id"
|
|
789
|
+
)
|
|
790
|
+
return optimization.continue_optimization(
|
|
791
|
+
run_id,
|
|
792
|
+
cfg=self._config,
|
|
793
|
+
candidate=candidate,
|
|
794
|
+
model=model,
|
|
795
|
+
credential_name=credential_name,
|
|
796
|
+
max_metric_calls=max_metric_calls,
|
|
797
|
+
auto=auto,
|
|
798
|
+
poll_interval=poll_interval,
|
|
799
|
+
timeout=timeout,
|
|
800
|
+
)
|
|
801
|
+
|
|
729
802
|
# -- data surface (flat verb-object over the client's credentials) -----
|
|
730
803
|
#
|
|
731
804
|
# Flat methods (create_valset_entry, list_assessments, get_trace, …), so the
|
|
@@ -747,6 +820,22 @@ class Client:
|
|
|
747
820
|
_exporter_pool.flush(self._config)
|
|
748
821
|
return programs.program_id_for(_http.ApiClient(self._config.api_key, self._config.endpoint), program)
|
|
749
822
|
|
|
823
|
+
def list_candidates(self, run_id: str) -> list[dict[str, Any]]:
|
|
824
|
+
"""The candidates of an optimization run, to choose one to continue from.
|
|
825
|
+
|
|
826
|
+
Each carries its ``candidate_id`` (``ca_…``), ``aggregate_score``,
|
|
827
|
+
``parent_candidate_id`` and ``instructions``, so a caller picks by what a
|
|
828
|
+
candidate is::
|
|
829
|
+
|
|
830
|
+
candidates = client.list_candidates("op_…")
|
|
831
|
+
chosen = max(candidates, key=lambda c: c["aggregate_score"])
|
|
832
|
+
client.continue_optimization("op_…", candidate=chosen["candidate_id"], max_metric_calls=120)
|
|
833
|
+
"""
|
|
834
|
+
self._check_active()
|
|
835
|
+
from . import optimization
|
|
836
|
+
|
|
837
|
+
return optimization.list_candidates(run_id, cfg=self._config)
|
|
838
|
+
|
|
750
839
|
def get_deployment_signature(self, deployment_id: str) -> DeploymentSignatureResponse:
|
|
751
840
|
"""Fetch one deployment's persisted artifact metadata."""
|
|
752
841
|
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
|