cmpnd 0.69.0__tar.gz → 0.71.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.69.0 → cmpnd-0.71.0}/PKG-INFO +1 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/__init__.py +2 -9
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/admin.py +1 -2
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/evals.py +13 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/client.py +10 -23
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/dataset_sync.py +8 -5
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/eval_handler.py +35 -9
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/models.py +13 -3
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/cli.md +14 -7
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/client.md +2 -7
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/sdk-instrumentation.md +2 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/pyproject.toml +1 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_evals.py +16 -2
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_main.py +22 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_parity.py +10 -5
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client.py +27 -16
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client_program_names.py +0 -2
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval.py +1 -1
- cmpnd-0.71.0/tests/test_eval_program_id.py +192 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_start.py +2 -2
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ingest_conformance.py +2 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_id_deprecation.py +0 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/uv.lock +1 -1
- {cmpnd-0.69.0 → cmpnd-0.71.0}/.gitignore +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/AGENTS.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/CLAUDE.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/context.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/drain.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_context.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_execute.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_integration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_models.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_xxh64.py +0 -0
|
@@ -171,15 +171,8 @@ def main() -> None:
|
|
|
171
171
|
evals.register(subparsers)
|
|
172
172
|
datasets.register(subparsers)
|
|
173
173
|
deployments.register(subparsers)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# CMPND_CLI_DEV=1 (mirroring the CMPND_CLI_ADMIN gate above). The env var
|
|
177
|
-
# only hides the commands from customers; the server still gates each action
|
|
178
|
-
# on the assessments:* / valsets:* scope, so this is discoverability, not
|
|
179
|
-
# enforcement.
|
|
180
|
-
if os.environ.get("CMPND_CLI_DEV") == "1":
|
|
181
|
-
assessments.register(subparsers)
|
|
182
|
-
valsets.register(subparsers)
|
|
174
|
+
assessments.register(subparsers)
|
|
175
|
+
valsets.register(subparsers)
|
|
183
176
|
|
|
184
177
|
# Top-level Docker-style shortcuts (human-readable by default; --json opts in)
|
|
185
178
|
top.register(subparsers)
|
|
@@ -14,8 +14,7 @@ default limits and feature flags, and `cmpnd admin signup …` sets who may sign
|
|
|
14
14
|
and the plan a new account's org lands on. `cmpnd admin feature-flags …` reads and
|
|
15
15
|
toggles the server's runtime flags. These hit
|
|
16
16
|
/api/v1/admin/* and require an API key carrying the admin:* scopes — the server
|
|
17
|
-
is the real authority. The CMPND_CLI_ADMIN env gate
|
|
18
|
-
only keeps these out of customers' --help; it grants nothing.
|
|
17
|
+
is the real authority. The CMPND_CLI_ADMIN env gate only keeps these out of customers' --help; it grants nothing.
|
|
19
18
|
"""
|
|
20
19
|
|
|
21
20
|
from __future__ import annotations
|
|
@@ -9,7 +9,18 @@ from .. import api_client, deprecation, pagination
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _add_list_args(p: ArgumentParser) -> None:
|
|
12
|
-
p.add_argument(
|
|
12
|
+
p.add_argument(
|
|
13
|
+
"--program",
|
|
14
|
+
dest="program_name",
|
|
15
|
+
metavar="NAME",
|
|
16
|
+
help="Only the runs of the program with this name, current or retired",
|
|
17
|
+
)
|
|
18
|
+
p.add_argument(
|
|
19
|
+
"--module",
|
|
20
|
+
dest="module_class",
|
|
21
|
+
metavar="CLASS",
|
|
22
|
+
help="Only the runs that evaluated this module class, matched exactly (e.g. ReAct)",
|
|
23
|
+
)
|
|
13
24
|
p.add_argument("--metric", dest="metric_name", help="Filter by metric name")
|
|
14
25
|
p.add_argument("--status", help="Filter by status (running, completed, failed, cancelled)")
|
|
15
26
|
pagination.add_args(p, with_page_aliases=True, default_limit=50)
|
|
@@ -63,6 +74,7 @@ def handle_list(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
63
74
|
body: dict[str, Any] = pagination.wire(args, "page_size")
|
|
64
75
|
for attr, key in [
|
|
65
76
|
("program_name", "program_name"),
|
|
77
|
+
("module_class", "module_class"),
|
|
66
78
|
("metric_name", "metric"),
|
|
67
79
|
("status", "status"),
|
|
68
80
|
]:
|
|
@@ -17,10 +17,6 @@ and propagates to its own eval / parallel threads. It registers nothing global
|
|
|
17
17
|
and holds no OS resource: exporters are pooled by credentials at module scope
|
|
18
18
|
(:mod:`cmpnd._exporter_pool`), so a client may fall out of scope with nothing to
|
|
19
19
|
release. ``close()`` is an optional alias for end-of-scope flushing.
|
|
20
|
-
|
|
21
|
-
The assessment and valset calls are in development. Each raises unless
|
|
22
|
-
``CMPND_CLI_DEV=1`` is set, the switch that hides the in-development
|
|
23
|
-
``cmpnd assessments`` and ``cmpnd valsets`` CLI groups. Tracing needs no flag.
|
|
24
20
|
"""
|
|
25
21
|
|
|
26
22
|
from __future__ import annotations
|
|
@@ -111,15 +107,6 @@ class Client:
|
|
|
111
107
|
if not self._active:
|
|
112
108
|
raise RuntimeError("client is closed; create a new cmpnd.Client")
|
|
113
109
|
|
|
114
|
-
def _check_in_development(self, method: str) -> None:
|
|
115
|
-
"""Refuse an assessment or valset call unless ``CMPND_CLI_DEV=1`` is set."""
|
|
116
|
-
if os.getenv("CMPND_CLI_DEV") != "1":
|
|
117
|
-
raise RuntimeError(
|
|
118
|
-
f"cmpnd.Client.{method}() is in development and not yet generally available. "
|
|
119
|
-
"Set CMPND_CLI_DEV=1 to enable it."
|
|
120
|
-
)
|
|
121
|
-
self._check_active()
|
|
122
|
-
|
|
123
110
|
def _scoped_callbacks(self) -> list[Any]:
|
|
124
111
|
"""This client's callback, plus the caller's own non-cmpnd callbacks.
|
|
125
112
|
|
|
@@ -918,7 +905,7 @@ class Client:
|
|
|
918
905
|
e.g. ``annotations=[("output", "/trends/2", "the third trend"),
|
|
919
906
|
("span", "a1b2c3", "wrong field")]``.
|
|
920
907
|
"""
|
|
921
|
-
self.
|
|
908
|
+
self._check_active()
|
|
922
909
|
_exporter_pool.flush(self._config) # the referenced trace must be durable first
|
|
923
910
|
return _assessments.create(
|
|
924
911
|
trace_id,
|
|
@@ -937,7 +924,7 @@ class Client:
|
|
|
937
924
|
Pass exactly one of ``program`` (all of that program's assessments, named by
|
|
938
925
|
its name or ``p_`` id) or ``trace_id`` (one trace's assessments).
|
|
939
926
|
"""
|
|
940
|
-
self.
|
|
927
|
+
self._check_active()
|
|
941
928
|
if program is not None and trace_id is not None:
|
|
942
929
|
raise ValueError("pass exactly one of program or trace_id")
|
|
943
930
|
page = _assessments.list(
|
|
@@ -952,24 +939,24 @@ class Client:
|
|
|
952
939
|
|
|
953
940
|
def get_assessment(self, assessment_id: str) -> dict[str, Any]:
|
|
954
941
|
"""Fetch one assessment with its annotations."""
|
|
955
|
-
self.
|
|
942
|
+
self._check_active()
|
|
956
943
|
return _assessments.get(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
957
944
|
|
|
958
945
|
def delete_assessment(self, assessment_id: str) -> None:
|
|
959
946
|
"""Delete one assessment. Raises if it does not exist."""
|
|
960
|
-
self.
|
|
947
|
+
self._check_active()
|
|
961
948
|
_assessments.delete(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
962
949
|
|
|
963
950
|
def create_valset(self, program: str, *, name: str | None = None) -> dict[str, Any]:
|
|
964
951
|
"""Create a valset owned by ``program``, a program name or ``p_`` id; name auto-assigned when omitted."""
|
|
965
|
-
self.
|
|
952
|
+
self._check_active()
|
|
966
953
|
return _valsets.create(
|
|
967
954
|
self._program_id(program), name=name, api_key=self._config.api_key, endpoint=self._config.endpoint
|
|
968
955
|
)
|
|
969
956
|
|
|
970
957
|
def list_valsets(self, program: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
|
|
971
958
|
"""The valsets of ``program``, a program name or ``p_`` id, newest first (paged by limit/offset)."""
|
|
972
|
-
self.
|
|
959
|
+
self._check_active()
|
|
973
960
|
page = _valsets.list(
|
|
974
961
|
self._program_id(program),
|
|
975
962
|
limit=limit,
|
|
@@ -981,12 +968,12 @@ class Client:
|
|
|
981
968
|
|
|
982
969
|
def get_valset(self, valset_id: str) -> dict[str, Any]:
|
|
983
970
|
"""Fetch one valset with its field shape and current version."""
|
|
984
|
-
self.
|
|
971
|
+
self._check_active()
|
|
985
972
|
return _valsets.get(valset_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
986
973
|
|
|
987
974
|
def list_valset_entries(self, valset_id: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
|
|
988
975
|
"""A valset's active entries (paged by limit/offset)."""
|
|
989
|
-
self.
|
|
976
|
+
self._check_active()
|
|
990
977
|
page = _valsets.list_entries(
|
|
991
978
|
valset_id, limit=limit, offset=offset, api_key=self._config.api_key, endpoint=self._config.endpoint
|
|
992
979
|
)
|
|
@@ -1002,7 +989,7 @@ class Client:
|
|
|
1002
989
|
) -> dict[str, Any]:
|
|
1003
990
|
"""Add one entry. Pass exactly one of ``from_assessment`` (the server
|
|
1004
991
|
derives inputs from its trace) or ``inputs``."""
|
|
1005
|
-
self.
|
|
992
|
+
self._check_active()
|
|
1006
993
|
return _valsets.create_entry(
|
|
1007
994
|
valset_id,
|
|
1008
995
|
expected_outputs=expected_outputs,
|
|
@@ -1014,7 +1001,7 @@ class Client:
|
|
|
1014
1001
|
|
|
1015
1002
|
def delete_valset_entry(self, entry_id: str) -> dict[str, Any]:
|
|
1016
1003
|
"""Retire an entry (versioned, not a hard delete)."""
|
|
1017
|
-
self.
|
|
1004
|
+
self._check_active()
|
|
1018
1005
|
return _valsets.delete_entry(entry_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
1019
1006
|
|
|
1020
1007
|
def _run_gepa(
|
|
@@ -15,7 +15,7 @@ from . import _http, configuration, identity, models
|
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def check_dataset_exists(dataset_hash: str) -> bool:
|
|
18
|
+
def check_dataset_exists(dataset_hash: str, config: configuration.Config | None = None) -> bool:
|
|
19
19
|
"""Check if a dataset with this hash already exists on the backend.
|
|
20
20
|
|
|
21
21
|
Makes a GET request to /api/v1/datasets/check/{dataset_hash}.
|
|
@@ -23,14 +23,17 @@ def check_dataset_exists(dataset_hash: str) -> bool:
|
|
|
23
23
|
|
|
24
24
|
Args:
|
|
25
25
|
dataset_hash: The SHA256[:16] hash of the dataset.
|
|
26
|
+
config: The account to ask, which must be the account the run publishes
|
|
27
|
+
to. None asks the process-global account.
|
|
26
28
|
|
|
27
29
|
Returns:
|
|
28
30
|
True if the dataset exists, False otherwise (including on errors).
|
|
29
31
|
"""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
if config is None:
|
|
33
|
+
try:
|
|
34
|
+
config = configuration.require_config()
|
|
35
|
+
except RuntimeError:
|
|
36
|
+
return False
|
|
34
37
|
|
|
35
38
|
url = f"{config.endpoint}/api/v1/datasets/check/{dataset_hash}"
|
|
36
39
|
|
|
@@ -10,7 +10,7 @@ import logging
|
|
|
10
10
|
from datetime import datetime, timezone
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
|
-
from . import context,
|
|
13
|
+
from . import context, helpers, identity, models
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
@@ -85,7 +85,7 @@ class EvalHandler:
|
|
|
85
85
|
logger.debug(f"Extracted program: {program}, type: {type(program) if program else None}")
|
|
86
86
|
|
|
87
87
|
if program:
|
|
88
|
-
eval_run.
|
|
88
|
+
eval_run.module_class = program.__class__.__name__
|
|
89
89
|
|
|
90
90
|
# Hash via the IR reflector on the live module so the class tag
|
|
91
91
|
# discriminates correctly; signature_summary is still derived from
|
|
@@ -165,16 +165,23 @@ class EvalHandler:
|
|
|
165
165
|
if not input_fields and devset and hasattr(devset[0], "_input_keys"):
|
|
166
166
|
input_fields = set(devset[0]._input_keys)
|
|
167
167
|
eval_run._input_fields = input_fields
|
|
168
|
-
# Fire pre-flight check (synchronous, short timeout)
|
|
168
|
+
# Fire pre-flight check (synchronous, short timeout). It asks the
|
|
169
|
+
# account the run publishes to: a client's own, else the global one.
|
|
169
170
|
from . import dataset_sync
|
|
170
171
|
|
|
171
172
|
try:
|
|
172
|
-
eval_run._dataset_exists = dataset_sync.check_dataset_exists(
|
|
173
|
+
eval_run._dataset_exists = dataset_sync.check_dataset_exists(
|
|
174
|
+
eval_run.dataset_hash, self._callback._own_config
|
|
175
|
+
)
|
|
173
176
|
except Exception:
|
|
174
177
|
eval_run._dataset_exists = None # Will include examples as fallback
|
|
175
178
|
|
|
179
|
+
exp = self._callback._current_exporter()
|
|
180
|
+
eval_run.program_id = self._program_id(exp)
|
|
181
|
+
|
|
176
182
|
logger.info(
|
|
177
|
-
f"EvalRun created:
|
|
183
|
+
f"EvalRun created: program_id={eval_run.program_id}, "
|
|
184
|
+
f"module_class={eval_run.module_class}, "
|
|
178
185
|
f"metric_name={eval_run.metric_name}, "
|
|
179
186
|
f"dataset_hash={eval_run.dataset_hash}, "
|
|
180
187
|
f"dataset_size={eval_run.dataset_size}"
|
|
@@ -184,7 +191,6 @@ class EvalHandler:
|
|
|
184
191
|
# the exporter (serve/observe, or deploy in-Lambda) assigns it. Obtain
|
|
185
192
|
# it synchronously now, before any eval trace ships, since every
|
|
186
193
|
# in-flight trace and the dict keys / span below are stamped with it.
|
|
187
|
-
exp = exporter.get_exporter()
|
|
188
194
|
if exp:
|
|
189
195
|
eval_run.eval_run_id = exp.export_eval_start(eval_run)
|
|
190
196
|
|
|
@@ -201,13 +207,33 @@ class EvalHandler:
|
|
|
201
207
|
|
|
202
208
|
# Capture evaluation config in span attributes
|
|
203
209
|
span.attributes["eval.run_id"] = str(eval_run.eval_run_id)
|
|
204
|
-
span.attributes["eval.
|
|
210
|
+
span.attributes["eval.module_class"] = eval_run.module_class or ""
|
|
205
211
|
span.attributes["eval.metric_name"] = eval_run.metric_name or ""
|
|
206
212
|
span.attributes["eval.dataset_size"] = str(eval_run.dataset_size)
|
|
207
213
|
|
|
208
214
|
self._callback._call_id_to_span[call_id] = span
|
|
209
215
|
context.push_span(span)
|
|
210
216
|
|
|
217
|
+
def _program_id(self, exp: Any) -> str | None:
|
|
218
|
+
"""The program id the eval run carries, resolved the way a trace's is.
|
|
219
|
+
|
|
220
|
+
A program name the call declares wins over the callback's program id. The
|
|
221
|
+
exporter resolves the name now, on the caller's thread, because the run's
|
|
222
|
+
start is sent synchronously and must carry the id. The exporter keeps the
|
|
223
|
+
answer for the process, so a name its traces already resolved costs no
|
|
224
|
+
request. A name the exporter cannot resolve leaves the run without an id.
|
|
225
|
+
"""
|
|
226
|
+
from . import callback
|
|
227
|
+
|
|
228
|
+
name = callback._declared_program_name()
|
|
229
|
+
if name is None:
|
|
230
|
+
return self._callback._resolve_program_id()
|
|
231
|
+
# Read with getattr because the member is optional: an in-memory collector
|
|
232
|
+
# that resolves no names has none.
|
|
233
|
+
resolve = getattr(exp, "resolve_program_name", None)
|
|
234
|
+
program_id = resolve(name) if callable(resolve) else None
|
|
235
|
+
return program_id if isinstance(program_id, str) else None
|
|
236
|
+
|
|
211
237
|
def on_evaluate_end(
|
|
212
238
|
self,
|
|
213
239
|
call_id: str,
|
|
@@ -228,7 +254,7 @@ class EvalHandler:
|
|
|
228
254
|
span.status = models.TraceStatus.OK
|
|
229
255
|
context.pop_span()
|
|
230
256
|
if self._callback._should_stream_span(span):
|
|
231
|
-
exp =
|
|
257
|
+
exp = self._callback._current_exporter()
|
|
232
258
|
if exp:
|
|
233
259
|
exp.export_span(span)
|
|
234
260
|
|
|
@@ -373,7 +399,7 @@ class EvalHandler:
|
|
|
373
399
|
span.attributes["eval.score"] = str(overall_score)
|
|
374
400
|
|
|
375
401
|
# Export the eval run
|
|
376
|
-
exp =
|
|
402
|
+
exp = self._callback._current_exporter()
|
|
377
403
|
if exp:
|
|
378
404
|
exp.export_eval_run(eval_run)
|
|
379
405
|
|
|
@@ -1274,7 +1274,11 @@ class EvalRunBuilder:
|
|
|
1274
1274
|
start_time: datetime | None = None
|
|
1275
1275
|
|
|
1276
1276
|
# Eval Identity (defines comparability)
|
|
1277
|
-
|
|
1277
|
+
# The program the run evaluates: the id serve gave the program name the call
|
|
1278
|
+
# declared, or the client's program id. None when the run names no program.
|
|
1279
|
+
program_id: str | None = None
|
|
1280
|
+
# The evaluated module's class, such as "ReAct".
|
|
1281
|
+
module_class: str | None = None
|
|
1278
1282
|
metric_name: str | None = None
|
|
1279
1283
|
dataset_hash: str | None = None
|
|
1280
1284
|
dataset_size: int = 0
|
|
@@ -1393,7 +1397,10 @@ class EvalRunBuilder:
|
|
|
1393
1397
|
return {
|
|
1394
1398
|
"eval_run_id": "new",
|
|
1395
1399
|
"status": EvalRunStatus.RUNNING.value,
|
|
1396
|
-
"
|
|
1400
|
+
"program_id": self.program_id,
|
|
1401
|
+
"module_class": self.module_class or "",
|
|
1402
|
+
# Also under the key a serve from before module_class reads.
|
|
1403
|
+
"program_name": self.module_class or "",
|
|
1397
1404
|
"metric_name": self.metric_name or "",
|
|
1398
1405
|
"dataset_hash": self.dataset_hash or "",
|
|
1399
1406
|
"dataset_size": self.dataset_size,
|
|
@@ -1411,7 +1418,10 @@ class EvalRunBuilder:
|
|
|
1411
1418
|
"""Convert to API-compatible dictionary."""
|
|
1412
1419
|
d = {
|
|
1413
1420
|
"eval_run_id": str(self.eval_run_id) if self.eval_run_id else None,
|
|
1414
|
-
"
|
|
1421
|
+
"program_id": self.program_id,
|
|
1422
|
+
"module_class": self.module_class or "",
|
|
1423
|
+
# Also under the key a serve from before module_class reads.
|
|
1424
|
+
"program_name": self.module_class or "",
|
|
1415
1425
|
"metric_name": self.metric_name or "",
|
|
1416
1426
|
"dataset_hash": self.dataset_hash or "",
|
|
1417
1427
|
"dataset_size": self.dataset_size,
|
|
@@ -418,10 +418,7 @@ down or neutral conclusion, an optional prose body and annotations. An
|
|
|
418
418
|
annotation attaches a note to a span or to a piece of the output addressed by
|
|
419
419
|
a JSON pointer.
|
|
420
420
|
|
|
421
|
-
|
|
422
|
-
`CMPND_CLI_DEV=1` is set, so it does not appear in `cmpnd --help`. The
|
|
423
|
-
variable only hides the commands. Serve still checks each action against the
|
|
424
|
-
`assessments:*` scopes.
|
|
421
|
+
Serve checks each action against the `assessments:*` scopes.
|
|
425
422
|
|
|
426
423
|
- `cmpnd assessments create <trace-id> [--up|--down|--neutral] [-m "prose"]
|
|
427
424
|
[--annotate KIND REF NOTE …]` records one judgement.
|
|
@@ -458,6 +455,18 @@ program signature hash. `cmpnd programs optimized` commands and
|
|
|
458
455
|
optimization result, not a program. Each group's `--help` names the column its
|
|
459
456
|
IDs come from.
|
|
460
457
|
|
|
458
|
+
`cmpnd evals list [--program NAME] [--module CLASS] [--metric] [--status]`
|
|
459
|
+
lists eval runs, newest first. `--program` takes the program's name, current
|
|
460
|
+
or retired, and a name no program answers to is an error that names it.
|
|
461
|
+
`--module` takes the evaluated module's class, such as `ReAct`, and matches it
|
|
462
|
+
exactly. The CLI sends them as `program_name` and `module_class`. Each eval
|
|
463
|
+
run in `evals list`, `evals show` and `programs evals` names what it evaluated
|
|
464
|
+
in three fields, as a trace does. `program_name` is the program's name, empty
|
|
465
|
+
when the program has none or the run names no program. `program_id` is the
|
|
466
|
+
program's `p_` id, and `module_class` is the evaluated module's class. A server
|
|
467
|
+
that predates `module_class` sends the class in `program_name` and filters
|
|
468
|
+
`--program` by class.
|
|
469
|
+
|
|
461
470
|
`cmpnd deployments openapi <id>` prints the OpenAPI document a deployment
|
|
462
471
|
serves, which an agent reads before it calls the deployment.
|
|
463
472
|
|
|
@@ -522,9 +531,7 @@ that lookup, so it creates a valset by the program's name. On a server from befo
|
|
|
522
531
|
name fails with an error that says to upgrade the server. Entries live in an
|
|
523
532
|
`entries` subgroup, the same shape as `cmpnd datasets examples`.
|
|
524
533
|
|
|
525
|
-
|
|
526
|
-
`CMPND_CLI_DEV=1` is set. Serve still checks each action against the
|
|
527
|
-
`valsets:*` scopes.
|
|
534
|
+
Serve checks each action against the `valsets:*` scopes.
|
|
528
535
|
|
|
529
536
|
- `cmpnd valsets create <program> [--name <name>]` creates a validation
|
|
530
537
|
set for a program. The valset ID is its identity, and the name is a label
|
|
@@ -10,11 +10,6 @@ client methods too, and have no form outside a client. A client holds its own ta
|
|
|
10
10
|
the global config that `auto_instrument()` reads, so both can run in one
|
|
11
11
|
process.
|
|
12
12
|
|
|
13
|
-
The client's assessment and valset calls are in development. Each one raises
|
|
14
|
-
`RuntimeError` unless `CMPND_CLI_DEV=1` is set. The same variable reveals the
|
|
15
|
-
in-development `cmpnd assessments` and `cmpnd valsets` CLI groups. Tracing
|
|
16
|
-
through a client needs no flag.
|
|
17
|
-
|
|
18
13
|
## Entry point
|
|
19
14
|
|
|
20
15
|
```python
|
|
@@ -218,12 +213,12 @@ methods:
|
|
|
218
213
|
file the deployment stores, or the archive-relative file `path` names.
|
|
219
214
|
`sdk.get_deployment_signature(deployment_id)` returns the selected
|
|
220
215
|
artifact's typed metadata. It reads no worker status or executions.
|
|
221
|
-
- Assessments
|
|
216
|
+
- Assessments:
|
|
222
217
|
`sdk.create_assessment(trace_id, conclusion=..., body=...,
|
|
223
218
|
annotations=...)`, `sdk.list_assessments(program=... | trace_id=...,
|
|
224
219
|
limit=..., offset=...)`, `sdk.get_assessment(assessment_id)` and
|
|
225
220
|
`sdk.delete_assessment(assessment_id)`.
|
|
226
|
-
- Valsets
|
|
221
|
+
- Valsets:
|
|
227
222
|
`sdk.create_valset(program, name=...)`, `sdk.list_valsets(program,
|
|
228
223
|
limit=..., offset=...)`, `sdk.get_valset(valset_id)`,
|
|
229
224
|
`sdk.list_valset_entries(valset_id, limit=..., offset=...)`,
|
|
@@ -727,6 +727,8 @@ What it captures beyond the normal span flow:
|
|
|
727
727
|
- An `EvalRunBuilder` (constructed at `eval_handler.py:79`) that groups all per-example traces under one eval ID.
|
|
728
728
|
- The metric name (via `get_metric_name` from `python-sdk/cmpnd/helpers.py`) and inferred provider.
|
|
729
729
|
- Links to the enclosing optimization run when one exists (`eval_handler.py:85`), so eval runs triggered inside `GEPA.compile` roll up under the optimization in the UI.
|
|
730
|
+
- The program the run evaluates, as `program_id`. A program name the call declares wins: the exporter resolves it with `resolve_program_name`, the same once-per-process answer its traces use, on the caller's thread because the eval start is sent synchronously. Without a declared name, the run takes the callback's program id. A name serve refuses leaves the run without an id. The evaluated module's class goes as `module_class`, and again under `program_name`, the key a serve from before `module_class` reads.
|
|
731
|
+
- The exporter it publishes through: the callback's own (`_current_exporter`), so a client's eval runs go to the client's account.
|
|
730
732
|
- The dataset — on `on_evaluate_start` it triggers the `dataset_sync` pre-flight described above.
|
|
731
733
|
|
|
732
734
|
Per-example results (scores, statuses, example hashes) are collected in `on_evaluate_end` and shipped as part of the `EvalRunBuilder`'s `to_api_dict()`, which the exporter routes to `/api/v1/eval_runs`.
|
|
@@ -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.71.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -86,20 +86,34 @@ class TestEvalsList:
|
|
|
86
86
|
# own spelling passes while the filter does nothing.
|
|
87
87
|
def test_minimal_list(self, mock_client):
|
|
88
88
|
mock_client.post.return_value = {"eval_runs": []}
|
|
89
|
-
args = argparse.Namespace(
|
|
89
|
+
args = argparse.Namespace(
|
|
90
|
+
program_name=None, module_class=None, metric_name=None, status=None, limit=50, offset=0
|
|
91
|
+
)
|
|
90
92
|
handle_list(mock_client, args)
|
|
91
93
|
body = mock_client.post.call_args[1]["json"]
|
|
92
94
|
assert body == {"page": 1, "page_size": 50}
|
|
93
95
|
|
|
94
96
|
def test_with_filters(self, mock_client):
|
|
95
97
|
mock_client.post.return_value = {"eval_runs": []}
|
|
96
|
-
args = argparse.Namespace(
|
|
98
|
+
args = argparse.Namespace(
|
|
99
|
+
program_name="RAG", module_class=None, metric_name="accuracy", status="completed", limit=50, offset=0
|
|
100
|
+
)
|
|
97
101
|
handle_list(mock_client, args)
|
|
98
102
|
body = mock_client.post.call_args[1]["json"]
|
|
99
103
|
assert body["program_name"] == "RAG"
|
|
100
104
|
assert body["metric"] == "accuracy"
|
|
101
105
|
assert body["status"] == "completed"
|
|
102
106
|
|
|
107
|
+
def test_program_names_the_program_and_module_names_the_class(self, mock_client):
|
|
108
|
+
# --program is the program's name; --module is the evaluated module's
|
|
109
|
+
# class, which the server matches exactly under module_class.
|
|
110
|
+
mock_client.post.return_value = {"eval_runs": []}
|
|
111
|
+
args = _build_parser().parse_args(["evals", "list", "--program", "capital-qa", "--module", "ReAct"])
|
|
112
|
+
handle_list(mock_client, args)
|
|
113
|
+
body = mock_client.post.call_args[1]["json"]
|
|
114
|
+
assert body["program_name"] == "capital-qa"
|
|
115
|
+
assert body["module_class"] == "ReAct"
|
|
116
|
+
|
|
103
117
|
def test_deprecated_search_verb_dispatches_and_is_marked(self, mock_client):
|
|
104
118
|
# The warning is the dispatcher's job (see test_main.py); the wiring is this one's.
|
|
105
119
|
parser = _build_parser()
|
|
@@ -169,6 +169,28 @@ class TestDevGate:
|
|
|
169
169
|
output = json.loads(captured.out)
|
|
170
170
|
assert "families" in output
|
|
171
171
|
|
|
172
|
+
def test_assessments_works_without_flag(self, capsys):
|
|
173
|
+
env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
|
|
174
|
+
env["CMPND_API_KEY"] = "test-key"
|
|
175
|
+
mock_response = {"assessments": [], "total": 0}
|
|
176
|
+
with mock.patch("sys.argv", ["cmpnd", "assessments", "list", "--trace", "t_1"]):
|
|
177
|
+
with mock.patch.dict(os.environ, env, clear=True):
|
|
178
|
+
with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
|
|
179
|
+
main()
|
|
180
|
+
assert get.call_args.args[1] == "/api/v1/assessments"
|
|
181
|
+
assert json.loads(capsys.readouterr().out) == mock_response
|
|
182
|
+
|
|
183
|
+
def test_valsets_works_without_flag(self, capsys):
|
|
184
|
+
env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
|
|
185
|
+
env["CMPND_API_KEY"] = "test-key"
|
|
186
|
+
mock_response = {"id": "v_1", "name": "valset-2026-11-02"}
|
|
187
|
+
with mock.patch("sys.argv", ["cmpnd", "valsets", "show", "v_1"]):
|
|
188
|
+
with mock.patch.dict(os.environ, env, clear=True):
|
|
189
|
+
with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
|
|
190
|
+
main()
|
|
191
|
+
assert get.call_args.args[1] == "/api/v1/valsets/v_1"
|
|
192
|
+
assert json.loads(capsys.readouterr().out) == mock_response
|
|
193
|
+
|
|
172
194
|
|
|
173
195
|
class TestAdminGate:
|
|
174
196
|
"""CMP-126: `admin` commands gated behind CMPND_CLI_ADMIN=1; the
|
|
@@ -16,7 +16,6 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
18
|
import itertools
|
|
19
|
-
import os
|
|
20
19
|
import re
|
|
21
20
|
from pathlib import Path
|
|
22
21
|
from unittest import mock
|
|
@@ -26,6 +25,9 @@ from cmpnd.cli.api_client import ApiClient
|
|
|
26
25
|
from cmpnd.cli.commands import (
|
|
27
26
|
admin as _admin,
|
|
28
27
|
)
|
|
28
|
+
from cmpnd.cli.commands import (
|
|
29
|
+
assessments as _assessments,
|
|
30
|
+
)
|
|
29
31
|
from cmpnd.cli.commands import (
|
|
30
32
|
auth as _auth,
|
|
31
33
|
)
|
|
@@ -59,6 +61,9 @@ from cmpnd.cli.commands import (
|
|
|
59
61
|
from cmpnd.cli.commands import (
|
|
60
62
|
traces as _traces,
|
|
61
63
|
)
|
|
64
|
+
from cmpnd.cli.commands import (
|
|
65
|
+
valsets as _valsets,
|
|
66
|
+
)
|
|
62
67
|
|
|
63
68
|
#: Every module registering a resource-tier noun group. `login` is excluded
|
|
64
69
|
#: deliberately: `login` / `logout` are task-tier top-level commands with no
|
|
@@ -75,6 +80,8 @@ _RESOURCE_MODULES = (
|
|
|
75
80
|
_evals,
|
|
76
81
|
_datasets,
|
|
77
82
|
_deployments,
|
|
83
|
+
_assessments,
|
|
84
|
+
_valsets,
|
|
78
85
|
)
|
|
79
86
|
|
|
80
87
|
|
|
@@ -281,10 +288,8 @@ class TestOptimizeBinding:
|
|
|
281
288
|
partial revival (CLI but not REPL) is the failure worth catching."""
|
|
282
289
|
|
|
283
290
|
def test_optimize_is_bound_on_both_surfaces(self):
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
assert "optimize" in _argparse_subcommands()
|
|
287
|
-
assert "optimize" in _shell_namespace()
|
|
291
|
+
assert "optimize" in _argparse_subcommands()
|
|
292
|
+
assert "optimize" in _shell_namespace()
|
|
288
293
|
|
|
289
294
|
|
|
290
295
|
class TestResourceVocabulary:
|
|
@@ -327,11 +327,11 @@ class TestMisuseGuard:
|
|
|
327
327
|
sdk5.run_program(a_program(), question="What is the capital of France?")
|
|
328
328
|
|
|
329
329
|
|
|
330
|
-
class
|
|
331
|
-
"""The client's
|
|
332
|
-
|
|
330
|
+
class TestAssessmentsAndValsetsNeedNoFlag:
|
|
331
|
+
"""The client's assessment and valset calls need no environment flag. A closed
|
|
332
|
+
client still refuses each one, as it refuses every other call."""
|
|
333
333
|
|
|
334
|
-
|
|
334
|
+
CALLS = {
|
|
335
335
|
"create_assessment": ("t_1",),
|
|
336
336
|
"list_assessments": ("p_0123456789Ab",),
|
|
337
337
|
"get_assessment": ("a_1",),
|
|
@@ -344,23 +344,19 @@ class TestDevelopmentGate:
|
|
|
344
344
|
"delete_valset_entry": ("e_1",),
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
sdk = cmpnd.Client(project_tags=["context-Z"], api_key="k", endpoint="http://x")
|
|
350
|
-
assert sdk._active
|
|
351
|
-
|
|
352
|
-
@pytest.mark.parametrize("method", sorted(GATED))
|
|
353
|
-
def test_an_assessment_or_valset_call_refuses_without_the_flag(self, method, monkeypatch: pytest.MonkeyPatch):
|
|
347
|
+
@pytest.mark.parametrize("method", sorted(CALLS))
|
|
348
|
+
def test_a_closed_client_refuses_an_assessment_or_valset_call(self, method, monkeypatch: pytest.MonkeyPatch):
|
|
354
349
|
monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
|
|
355
350
|
sdk = cmpnd.Client(api_key="k", endpoint="http://x")
|
|
351
|
+
sdk.close()
|
|
356
352
|
kwargs = {"expected_outputs": {}} if method == "create_valset_entry" else {}
|
|
357
|
-
with pytest.raises(RuntimeError, match=r"
|
|
358
|
-
getattr(sdk, method)(*self.
|
|
353
|
+
with pytest.raises(RuntimeError, match=r"client is closed"):
|
|
354
|
+
getattr(sdk, method)(*self.CALLS[method], **kwargs)
|
|
359
355
|
|
|
360
|
-
def
|
|
356
|
+
def test_every_assessment_and_valset_method_is_listed(self):
|
|
361
357
|
public = {name for name in dir(cmpnd.Client) if not name.startswith("_")}
|
|
362
358
|
data = {name for name in public if "assessment" in name or "valset" in name}
|
|
363
|
-
assert data == set(self.
|
|
359
|
+
assert data == set(self.CALLS)
|
|
364
360
|
|
|
365
361
|
|
|
366
362
|
# --- Case 7: exceptions and cleanup --------------------------------------
|
|
@@ -794,7 +790,7 @@ class TestClientDataSurface:
|
|
|
794
790
|
client's own credentials, list_* unwrap to lists, and client.traces warns."""
|
|
795
791
|
|
|
796
792
|
def _client(self, monkeypatch):
|
|
797
|
-
monkeypatch.
|
|
793
|
+
monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
|
|
798
794
|
monkeypatch.setattr(cmpnd.client._exporter_pool, "flush", lambda cfg: None)
|
|
799
795
|
return cmpnd.Client(api_key="k", endpoint="http://x")
|
|
800
796
|
|
|
@@ -811,6 +807,21 @@ class TestClientDataSurface:
|
|
|
811
807
|
assert seen["trace_id"] == "t-1" and seen["conclusion"] == "down"
|
|
812
808
|
assert seen["api_key"] == "k" and seen["endpoint"] == "http://x"
|
|
813
809
|
|
|
810
|
+
@pytest.mark.parametrize(
|
|
811
|
+
("method", "module", "function", "ref"),
|
|
812
|
+
[
|
|
813
|
+
("get_assessment", "_assessments", "get", "as_1"),
|
|
814
|
+
("get_valset", "_valsets", "get", "v_1"),
|
|
815
|
+
("delete_valset_entry", "_valsets", "delete_entry", "e_1"),
|
|
816
|
+
],
|
|
817
|
+
)
|
|
818
|
+
def test_a_one_id_call_delegates_with_client_creds(self, method, module, function, ref, monkeypatch):
|
|
819
|
+
fake = mock.create_autospec(getattr(getattr(cmpnd, module), function), return_value={"id": ref})
|
|
820
|
+
monkeypatch.setattr(getattr(cmpnd, module), function, fake)
|
|
821
|
+
|
|
822
|
+
assert getattr(self._client(monkeypatch), method)(ref) == {"id": ref}
|
|
823
|
+
fake.assert_called_once_with(ref, api_key="k", endpoint="http://x")
|
|
824
|
+
|
|
814
825
|
def test_get_deployment_signature_delegates_with_client_creds(self, monkeypatch):
|
|
815
826
|
seen: dict = {}
|
|
816
827
|
answer = object()
|
|
@@ -126,7 +126,6 @@ def _provider():
|
|
|
126
126
|
|
|
127
127
|
@pytest.fixture(autouse=True)
|
|
128
128
|
def _clean_slate(monkeypatch: pytest.MonkeyPatch):
|
|
129
|
-
monkeypatch.delenv("CMPND_CLI_DEV", raising=False) # a client traces with no dev flag
|
|
130
129
|
monkeypatch.delenv("CMPND_PROGRAM_ID", raising=False)
|
|
131
130
|
configuration._config = None
|
|
132
131
|
saved_callbacks = list(dspy.settings.callbacks or [])
|
|
@@ -328,7 +327,6 @@ def minting_server(monkeypatch: pytest.MonkeyPatch):
|
|
|
328
327
|
def _new_client(**kw: Any) -> httpx.Client:
|
|
329
328
|
return real_new_client(transport=httpx.MockTransport(srv.handler), **kw)
|
|
330
329
|
|
|
331
|
-
monkeypatch.setenv("CMPND_CLI_DEV", "1")
|
|
332
330
|
with (
|
|
333
331
|
mock.patch("cmpnd._http.new_client", autospec=True, side_effect=_new_client),
|
|
334
332
|
mock.patch("cmpnd.exporter_http.BatchExporter", autospec=True, side_effect=_factory),
|