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