cmpnd 0.69.0__tar.gz → 0.70.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.70.0}/PKG-INFO +1 -1
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/evals.py +13 -1
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/dataset_sync.py +8 -5
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/eval_handler.py +35 -9
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/models.py +13 -3
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/cli.md +12 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/sdk-instrumentation.md +2 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/pyproject.toml +1 -1
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_evals.py +16 -2
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_eval.py +1 -1
- cmpnd-0.70.0/tests/test_eval_program_id.py +192 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_eval_start.py +2 -2
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_ingest_conformance.py +2 -1
- {cmpnd-0.69.0 → cmpnd-0.70.0}/uv.lock +1 -1
- {cmpnd-0.69.0 → cmpnd-0.70.0}/.gitignore +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/AGENTS.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/CLAUDE.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/context.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/client.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/drain.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_client.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_context.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_execute.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_integration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_models.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_retry.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.69.0 → cmpnd-0.70.0}/tests/test_xxh64.py +0 -0
|
@@ -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
|
]:
|
|
@@ -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,
|
|
@@ -458,6 +458,18 @@ program signature hash. `cmpnd programs optimized` commands and
|
|
|
458
458
|
optimization result, not a program. Each group's `--help` names the column its
|
|
459
459
|
IDs come from.
|
|
460
460
|
|
|
461
|
+
`cmpnd evals list [--program NAME] [--module CLASS] [--metric] [--status]`
|
|
462
|
+
lists eval runs, newest first. `--program` takes the program's name, current
|
|
463
|
+
or retired, and a name no program answers to is an error that names it.
|
|
464
|
+
`--module` takes the evaluated module's class, such as `ReAct`, and matches it
|
|
465
|
+
exactly. The CLI sends them as `program_name` and `module_class`. Each eval
|
|
466
|
+
run in `evals list`, `evals show` and `programs evals` names what it evaluated
|
|
467
|
+
in three fields, as a trace does. `program_name` is the program's name, empty
|
|
468
|
+
when the program has none or the run names no program. `program_id` is the
|
|
469
|
+
program's `p_` id, and `module_class` is the evaluated module's class. A server
|
|
470
|
+
that predates `module_class` sends the class in `program_name` and filters
|
|
471
|
+
`--program` by class.
|
|
472
|
+
|
|
461
473
|
`cmpnd deployments openapi <id>` prints the OpenAPI document a deployment
|
|
462
474
|
serves, which an agent reads before it calls the deployment.
|
|
463
475
|
|
|
@@ -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.70.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()
|
|
@@ -199,7 +199,7 @@ class TestEvalLifecycle:
|
|
|
199
199
|
eval_run = exporter.eval_runs[0]
|
|
200
200
|
|
|
201
201
|
# Program metadata
|
|
202
|
-
assert eval_run.
|
|
202
|
+
assert eval_run.module_class == "TestProgram"
|
|
203
203
|
assert eval_run.metric_name == "exact_match"
|
|
204
204
|
assert eval_run.dataset_size == 3
|
|
205
205
|
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""An eval run names its program by id, and its module by class.
|
|
2
|
+
|
|
3
|
+
The SDK resolves the program name a call declares to the program's id, once per
|
|
4
|
+
process through the exporter, and sends it as ``program_id`` on the eval run's
|
|
5
|
+
start and completion. The evaluated module's class goes as ``module_class``, and
|
|
6
|
+
again under ``program_name``, where a serve from before ``module_class`` reads it.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from unittest import mock
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from tests import _traced_run
|
|
15
|
+
from tests._exporter_helpers import decode_body
|
|
16
|
+
|
|
17
|
+
pytest.importorskip("dspy")
|
|
18
|
+
|
|
19
|
+
import dspy # noqa: E402
|
|
20
|
+
|
|
21
|
+
from cmpnd import _http, configuration # noqa: E402
|
|
22
|
+
from cmpnd.callback import DECLARED_PROGRAM_SETTING # noqa: E402
|
|
23
|
+
from cmpnd.configuration import Config, configure # noqa: E402
|
|
24
|
+
from cmpnd.context import clear_context # noqa: E402
|
|
25
|
+
from cmpnd.exporter import BatchExporter # noqa: E402
|
|
26
|
+
from cmpnd.models import EvalRunBuilder # noqa: E402
|
|
27
|
+
from tests.test_eval import MockExporter # noqa: E402
|
|
28
|
+
|
|
29
|
+
PROGRAM_ID = "p_3pQr7t8sK2mN"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_the_start_and_the_completion_carry_the_program_id_and_the_class():
|
|
33
|
+
eval_run = EvalRunBuilder(module_class="ReAct", program_id=PROGRAM_ID, metric_name="m")
|
|
34
|
+
for body in (eval_run.to_start_dict(), eval_run.to_api_dict()):
|
|
35
|
+
assert body["program_id"] == PROGRAM_ID
|
|
36
|
+
assert body["module_class"] == "ReAct"
|
|
37
|
+
assert body["program_name"] == "ReAct"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_a_run_with_no_program_sends_no_id():
|
|
41
|
+
eval_run = EvalRunBuilder(module_class="Predict")
|
|
42
|
+
for body in (eval_run.to_start_dict(), eval_run.to_api_dict()):
|
|
43
|
+
assert body["program_id"] is None
|
|
44
|
+
assert body["module_class"] == "Predict"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_the_start_puts_the_program_id_on_the_wire():
|
|
48
|
+
captured = {}
|
|
49
|
+
|
|
50
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
51
|
+
captured["body"] = decode_body(request)
|
|
52
|
+
return httpx.Response(202, json={"eval_run_id": "ev_SERVERMINTED"})
|
|
53
|
+
|
|
54
|
+
config = Config(api_key="test", endpoint="http://localhost:9999")
|
|
55
|
+
exporter = BatchExporter(config, transport=httpx.MockTransport(handler))
|
|
56
|
+
exporter.export_eval_start(EvalRunBuilder(module_class="ReAct", program_id=PROGRAM_ID))
|
|
57
|
+
|
|
58
|
+
assert captured["body"]["program_id"] == PROGRAM_ID
|
|
59
|
+
assert captured["body"]["module_class"] == "ReAct"
|
|
60
|
+
assert captured["body"]["program_name"] == "ReAct"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class QuestionAnswer(dspy.Module):
|
|
64
|
+
def __init__(self):
|
|
65
|
+
super().__init__()
|
|
66
|
+
self.predict = dspy.Predict("question -> answer")
|
|
67
|
+
|
|
68
|
+
def forward(self, question):
|
|
69
|
+
return self.predict(question=question)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _exact(example, prediction, trace=None):
|
|
73
|
+
return example.answer == prediction.answer
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ResolvingExporter(MockExporter):
|
|
77
|
+
"""A MockExporter that resolves declared program names, as BatchExporter does."""
|
|
78
|
+
|
|
79
|
+
def __init__(self, ids: dict[str, str | None]):
|
|
80
|
+
super().__init__()
|
|
81
|
+
self.ids = ids
|
|
82
|
+
self.resolved: list[str] = []
|
|
83
|
+
|
|
84
|
+
def resolve_program_name(self, name: str) -> str | None:
|
|
85
|
+
self.resolved.append(name)
|
|
86
|
+
return self.ids.get(name)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class TestTheEvalHandlerNamesTheProgram:
|
|
90
|
+
def setup_method(self):
|
|
91
|
+
configure(api_key="test_key", endpoint="http://localhost:8000")
|
|
92
|
+
|
|
93
|
+
def teardown_method(self):
|
|
94
|
+
clear_context()
|
|
95
|
+
import cmpnd.configuration
|
|
96
|
+
|
|
97
|
+
cmpnd.configuration._config = None
|
|
98
|
+
|
|
99
|
+
def _start(self, exporter, *, declared: str | None = None, callback=None):
|
|
100
|
+
callback = callback or _traced_run.make_callback()
|
|
101
|
+
evaluate = dspy.Evaluate(devset=[], metric=_exact)
|
|
102
|
+
settings = {DECLARED_PROGRAM_SETTING: declared} if declared is not None else {}
|
|
103
|
+
with mock.patch("cmpnd.exporter.get_exporter", autospec=True, return_value=exporter), dspy.context(**settings):
|
|
104
|
+
callback.on_evaluate_start(call_id="c", instance=evaluate, inputs={"program": QuestionAnswer()})
|
|
105
|
+
return exporter.eval_starts[0]
|
|
106
|
+
|
|
107
|
+
def test_a_declared_name_resolves_to_its_program_id(self):
|
|
108
|
+
exporter = ResolvingExporter({"capital-qa": PROGRAM_ID})
|
|
109
|
+
eval_run = self._start(exporter, declared="capital-qa")
|
|
110
|
+
assert exporter.resolved == ["capital-qa"]
|
|
111
|
+
assert eval_run.program_id == PROGRAM_ID
|
|
112
|
+
assert eval_run.module_class == "QuestionAnswer"
|
|
113
|
+
|
|
114
|
+
def test_a_name_serve_refuses_sends_no_id(self):
|
|
115
|
+
exporter = ResolvingExporter({})
|
|
116
|
+
eval_run = self._start(exporter, declared="capital-qa")
|
|
117
|
+
assert eval_run.program_id is None
|
|
118
|
+
|
|
119
|
+
def test_the_callbacks_program_id_applies_when_no_name_is_declared(self):
|
|
120
|
+
callback = _traced_run.make_callback()
|
|
121
|
+
exporter = ResolvingExporter({})
|
|
122
|
+
with mock.patch.object(callback, "_resolve_program_id", autospec=True, return_value=PROGRAM_ID):
|
|
123
|
+
eval_run = self._start(exporter, callback=callback)
|
|
124
|
+
assert exporter.resolved == []
|
|
125
|
+
assert eval_run.program_id == PROGRAM_ID
|
|
126
|
+
|
|
127
|
+
def test_a_declared_name_wins_over_the_callbacks_program_id(self):
|
|
128
|
+
callback = _traced_run.make_callback()
|
|
129
|
+
other = "p_000000000000"
|
|
130
|
+
exporter = ResolvingExporter({"capital-qa": PROGRAM_ID})
|
|
131
|
+
with mock.patch.object(callback, "_resolve_program_id", autospec=True, return_value=other):
|
|
132
|
+
eval_run = self._start(exporter, declared="capital-qa", callback=callback)
|
|
133
|
+
assert eval_run.program_id == PROGRAM_ID
|
|
134
|
+
|
|
135
|
+
def test_a_run_that_names_no_program_carries_no_id(self):
|
|
136
|
+
eval_run = self._start(MockExporter())
|
|
137
|
+
assert eval_run.program_id is None
|
|
138
|
+
assert eval_run.module_class == "QuestionAnswer"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
GLOBAL_ENDPOINT = "http://global-account.invalid"
|
|
142
|
+
CLIENT_ENDPOINT = "http://client-account.invalid"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TestTheDatasetPreflightAsksTheAccountTheRunPublishesTo:
|
|
146
|
+
"""The eval start asks serve whether the dataset exists, so the completion can
|
|
147
|
+
leave its examples out. It must ask the account the run publishes to: a client
|
|
148
|
+
publishes to its own account, which may lack a dataset the global one holds."""
|
|
149
|
+
|
|
150
|
+
def teardown_method(self):
|
|
151
|
+
clear_context()
|
|
152
|
+
configuration._config = None
|
|
153
|
+
|
|
154
|
+
def _start(self, callback):
|
|
155
|
+
"""Start an eval of a one-example devset, and return the eval run and the
|
|
156
|
+
(url, authorization) of every dataset check. Only the global account holds
|
|
157
|
+
the dataset."""
|
|
158
|
+
checks: list[tuple[str, str]] = []
|
|
159
|
+
|
|
160
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
161
|
+
authorization = request.headers["Authorization"]
|
|
162
|
+
checks.append((str(request.url), authorization))
|
|
163
|
+
return httpx.Response(200, json={"exists": authorization == "Bearer ck_global"})
|
|
164
|
+
|
|
165
|
+
real_new_client = _http.new_client
|
|
166
|
+
|
|
167
|
+
def new_client(**kwargs):
|
|
168
|
+
return real_new_client(transport=httpx.MockTransport(handler), **kwargs)
|
|
169
|
+
|
|
170
|
+
devset = [dspy.Example(question="2+2?", answer="4").with_inputs("question")]
|
|
171
|
+
evaluate = dspy.Evaluate(devset=devset, metric=_exact)
|
|
172
|
+
exporter = MockExporter()
|
|
173
|
+
with (
|
|
174
|
+
mock.patch("cmpnd._http.new_client", autospec=True, side_effect=new_client),
|
|
175
|
+
mock.patch("cmpnd.exporter.get_exporter", autospec=True, return_value=exporter),
|
|
176
|
+
mock.patch("cmpnd._exporter_pool.ensure_exporter_started", autospec=True, return_value=exporter),
|
|
177
|
+
):
|
|
178
|
+
callback.on_evaluate_start(call_id="c", instance=evaluate, inputs={"program": QuestionAnswer()})
|
|
179
|
+
return exporter.eval_starts[0], checks
|
|
180
|
+
|
|
181
|
+
def test_a_clients_eval_checks_the_clients_account(self):
|
|
182
|
+
configure(api_key="ck_global", endpoint=GLOBAL_ENDPOINT)
|
|
183
|
+
own = Config(api_key="ck_client", endpoint=CLIENT_ENDPOINT)
|
|
184
|
+
eval_run, checks = self._start(_traced_run.make_callback(own_config=own))
|
|
185
|
+
assert checks == [(f"{CLIENT_ENDPOINT}/api/v1/datasets/check/{eval_run.dataset_hash}", "Bearer ck_client")]
|
|
186
|
+
assert eval_run._dataset_exists is False
|
|
187
|
+
|
|
188
|
+
def test_the_global_callbacks_eval_checks_the_global_account(self):
|
|
189
|
+
configure(api_key="ck_global", endpoint=GLOBAL_ENDPOINT)
|
|
190
|
+
eval_run, checks = self._start(_traced_run.make_callback())
|
|
191
|
+
assert checks == [(f"{GLOBAL_ENDPOINT}/api/v1/datasets/check/{eval_run.dataset_hash}", "Bearer ck_global")]
|
|
192
|
+
assert eval_run._dataset_exists is True
|
|
@@ -32,7 +32,7 @@ def test_export_eval_start_is_synchronous_and_returns_server_id():
|
|
|
32
32
|
return httpx.Response(200, json={"eval_run_id": "ev_SERVERMINTED"})
|
|
33
33
|
|
|
34
34
|
exporter = BatchExporter(_config(), transport=httpx.MockTransport(handler))
|
|
35
|
-
eval_run = EvalRunBuilder(
|
|
35
|
+
eval_run = EvalRunBuilder(module_class="P", metric_name="m")
|
|
36
36
|
|
|
37
37
|
assigned = exporter.export_eval_start(eval_run)
|
|
38
38
|
|
|
@@ -76,7 +76,7 @@ def test_eval_start_fails_loud_after_retries():
|
|
|
76
76
|
return httpx.Response(500, json={"error": "boom"})
|
|
77
77
|
|
|
78
78
|
exporter = BatchExporter(_config(), transport=httpx.MockTransport(handler))
|
|
79
|
-
eval_run = EvalRunBuilder(
|
|
79
|
+
eval_run = EvalRunBuilder(module_class="P")
|
|
80
80
|
|
|
81
81
|
with pytest.raises(RuntimeError):
|
|
82
82
|
exporter.export_eval_start(eval_run)
|
|
@@ -249,7 +249,8 @@ def _eval_run() -> EvalRunBuilder:
|
|
|
249
249
|
now = datetime.now(timezone.utc)
|
|
250
250
|
run = EvalRunBuilder(
|
|
251
251
|
start_time=now,
|
|
252
|
-
|
|
252
|
+
program_id="p_3pQr7t8sK2mN",
|
|
253
|
+
module_class="QAProgram",
|
|
253
254
|
metric_name="exact_match",
|
|
254
255
|
dataset_hash="0123456789abcdef",
|
|
255
256
|
dataset_size=2,
|
|
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
|
|
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
|