cmpnd 0.63.0__tar.gz → 0.65.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmpnd-0.63.0 → cmpnd-0.65.0}/PKG-INFO +63 -51
- {cmpnd-0.63.0 → cmpnd-0.65.0}/README.md +62 -50
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_assessments.py +6 -5
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_traces.py +11 -14
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_valsets.py +9 -7
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/callback.py +25 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/__init__.py +0 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/assessments.py +11 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/evals.py +1 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/optimizations.py +117 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/programs.py +59 -16
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/top.py +37 -72
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/traces.py +8 -14
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/valsets.py +6 -25
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/shell.py +0 -4
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/verbs.py +6 -5
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/client.py +118 -29
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/execution.py +4 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimization.py +192 -116
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/programs.py +22 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/cli.md +94 -55
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/client.md +18 -10
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/reading-traces.md +2 -3
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/sdk-instrumentation.md +16 -3
- {cmpnd-0.63.0 → cmpnd-0.65.0}/pyproject.toml +1 -1
- cmpnd-0.65.0/tests/e2e/continuation_task.py +72 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_pandas.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_authored_metric.py +0 -2
- cmpnd-0.65.0/tests/e2e/test_optimize_continuation.py +120 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_custom_proposer.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_failures.py +0 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_loop.py +0 -3
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_traces_read.py +1 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_valsets_cli.py +11 -10
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/hosted_optimize_probe.py +0 -1
- cmpnd-0.65.0/tests/stress/test_optimize_continuation.py +156 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_optimize_loop.py +1 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_optimize_loop_wasm.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_optimize_stress.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_assessments_api.py +15 -5
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored_binding_credentials.py +3 -3
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored_metric_contract.py +5 -5
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored_named_models.py +0 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored_optimize.py +3 -3
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_assessments.py +34 -7
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_evals.py +1 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_optimizations.py +96 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_parity.py +0 -4
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_programs.py +90 -4
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_schema_sample.py +12 -8
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_shell.py +7 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_top.py +81 -10
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_traces.py +0 -4
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_traces_program_and_module.py +4 -5
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_traces_search_wire.py +28 -16
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_valsets.py +18 -14
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_client.py +12 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_client_program_names.py +142 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_credential_selection.py +6 -6
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deploy_program_id.py +11 -14
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_lm_configuration.py +1 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize.py +272 -81
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_budget.py +3 -4
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_proposer.py +0 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_program_names_in_deploy.py +3 -1
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_traces_read.py +0 -2
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_valsets_api.py +34 -8
- {cmpnd-0.63.0 → cmpnd-0.65.0}/uv.lock +1 -1
- cmpnd-0.63.0/cmpnd/cli/commands/signatures.py +0 -164
- cmpnd-0.63.0/tests/test_cli/test_signatures.py +0 -225
- {cmpnd-0.63.0 → cmpnd-0.65.0}/.gitignore +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/AGENTS.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/CLAUDE.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/context.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/models.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/references.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/README.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/release-stress.sh +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/drain.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/_provider.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/_readiness.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/_reliability.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/_result.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/mint_bedrock_token.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_bedrock_converse.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_deploy_programs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_multi_client_stress.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_optimize_client_committee.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_provider_roles.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_readiness.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_real_provider_twins.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_reliability.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_reliability_classify.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_rlm_wasm.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/stress/test_trace_search.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_callback.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_context.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_eval.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_execute.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_integration.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_models.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_release_stress_script.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_retry.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.63.0 → cmpnd-0.65.0}/tests/test_xxh64.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cmpnd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.65.0
|
|
4
4
|
Summary: DSPy observability and deployment SDK for cmpnd
|
|
5
5
|
Project-URL: Homepage, https://cmpnd.ai
|
|
6
6
|
Author-email: cmpnd <hello@cmpnd.ai>
|
|
@@ -51,9 +51,9 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
|
|
52
52
|
# cmpnd
|
|
53
53
|
|
|
54
|
-
The `cmpnd` package traces
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
The `cmpnd` package traces, deploys and optimizes DSPy programs on the cmpnd
|
|
55
|
+
platform. You give a program a name, and a client records its traces,
|
|
56
|
+
deployments and optimization runs under that name.
|
|
57
57
|
|
|
58
58
|
## Installation
|
|
59
59
|
|
|
@@ -66,46 +66,15 @@ uv add cmpnd # or: pip install cmpnd
|
|
|
66
66
|
The `cmpnd` library works with the cmpnd service at
|
|
67
67
|
[platform.cmpnd.ai](https://platform.cmpnd.ai). Create an API key on the
|
|
68
68
|
platform under Settings → API keys, and pass it as `api_key=` to
|
|
69
|
-
`cmpnd.
|
|
69
|
+
`cmpnd.Client()` or `cmpnd.configure()`. For a self-hosted cmpnd install, also
|
|
70
70
|
pass the install's URL as `endpoint=`.
|
|
71
71
|
|
|
72
72
|
## Quick start
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
import cmpnd
|
|
80
|
-
import dspy
|
|
81
|
-
|
|
82
|
-
cmpnd.configure(api_key="ck_xxx", project_tags="my-project")
|
|
83
|
-
cmpnd.auto_instrument()
|
|
84
|
-
|
|
85
|
-
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
|
|
86
|
-
|
|
87
|
-
cot = dspy.ChainOfThought("question -> answer")
|
|
88
|
-
result = cot(question="What is DSPy?") # the trace goes to cmpnd
|
|
89
|
-
|
|
90
|
-
cmpnd.trace_id(result) # "a1b2c3d4-...", or None outside instrumentation
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
`cmpnd.trace_id()` links a result to its platform trace, for example to attach
|
|
94
|
-
feedback later. Traces recorded this way have no program name. The platform
|
|
95
|
-
groups them by the structure of the program's modules. The API reference
|
|
96
|
-
below lists the other options of `cmpnd.configure()`.
|
|
97
|
-
|
|
98
|
-
## Program names
|
|
99
|
-
|
|
100
|
-
When you’re ready to name programs, evolve them, and share them with your team, switch
|
|
101
|
-
to `cmpnd.Client`. A client replaces `configure()` and `auto_instrument()` and offers
|
|
102
|
-
more features. A client records only the programs you run through it, and each of
|
|
103
|
-
those programs has a program name. A client takes most of the same arguments as `configure()`.
|
|
104
|
-
|
|
105
|
-
A program name is the name your organization gives a program, such as `question-answerer`.
|
|
106
|
-
Traces, deployments and optimization runs under one program name go to one
|
|
107
|
-
program. The platform makes the program the first time your organization uses
|
|
108
|
-
the program name.
|
|
74
|
+
A program name is the name your organization gives a program, such as
|
|
75
|
+
`question-answerer`. Traces, deployments and optimization runs under one
|
|
76
|
+
program name go to one program. The platform makes the program the first time
|
|
77
|
+
your organization uses the program name.
|
|
109
78
|
|
|
110
79
|
`@cmpnd.program(name)` above a `dspy.Module` class gives the class a program
|
|
111
80
|
name. Building the class takes its own arguments and a required `lm=`. The
|
|
@@ -128,17 +97,23 @@ class QA(dspy.Predict):
|
|
|
128
97
|
qa1 = QA(lm=dspy.LM("openai/gpt-6-luna"))
|
|
129
98
|
```
|
|
130
99
|
|
|
131
|
-
A
|
|
100
|
+
A `cmpnd.Client` runs the program and records its trace under the program
|
|
101
|
+
name:
|
|
132
102
|
|
|
133
103
|
```python
|
|
134
104
|
gepa = dspy.GEPA(metric=metric, reflection_lm=dspy.LM("openai/gpt-6-luna"), auto="light")
|
|
135
105
|
|
|
136
106
|
with cmpnd.Client(api_key="ck_xxx", project_tags="my-project") as sdk:
|
|
137
|
-
# the trace
|
|
107
|
+
# the trace goes to the program "question-answerer"
|
|
138
108
|
result = sdk.run_program(qa1, question="What is DSPy?")
|
|
139
109
|
qa2 = sdk.optimize_program(qa1, gepa, trainset=train, valset=val)
|
|
110
|
+
|
|
111
|
+
cmpnd.trace_id(result) # "a1b2c3d4-...", the trace of this run
|
|
140
112
|
```
|
|
141
113
|
|
|
114
|
+
`cmpnd.trace_id()` links a result to its platform trace, for example to attach
|
|
115
|
+
feedback later. A client records only the programs you run through it.
|
|
116
|
+
|
|
142
117
|
A client is active from construction. The `with` form flushes the client's
|
|
143
118
|
traces and closes it on exit. Without `with`, the client stays active until
|
|
144
119
|
you call `close()` or the process exits, and its traces go out at exit:
|
|
@@ -167,8 +142,26 @@ qa3 = cmpnd.Program(
|
|
|
167
142
|
- `optimize_program` runs the optimizer in your process and returns a copy of
|
|
168
143
|
the program that holds the optimized module. The copy keeps the program name
|
|
169
144
|
and the LM.
|
|
170
|
-
|
|
171
|
-
|
|
145
|
+
|
|
146
|
+
## Sketching with `auto_instrument()`
|
|
147
|
+
|
|
148
|
+
`cmpnd.auto_instrument()` records a trace of every DSPy call in the process,
|
|
149
|
+
with no other change to your code. Use it to sketch a
|
|
150
|
+
[DSPy program](https://dspy.ai/) and see what it does:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
cmpnd.configure(api_key="ck_xxx", project_tags="my-project")
|
|
154
|
+
cmpnd.auto_instrument()
|
|
155
|
+
|
|
156
|
+
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
|
|
157
|
+
dspy.ChainOfThought("question -> answer")(question="What is DSPy?")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
These traces carry no program, so the platform files them under Unattributed.
|
|
161
|
+
The first one in a process logs a warning that points to `@cmpnd.program` and
|
|
162
|
+
`cmpnd.Client`. Calling a `cmpnd.Program` directly while `auto_instrument()` is
|
|
163
|
+
on raises a `TypeError` that points to the client. The API reference below
|
|
164
|
+
lists the options of `cmpnd.configure()`.
|
|
172
165
|
|
|
173
166
|
## Deployed programs
|
|
174
167
|
|
|
@@ -504,14 +497,12 @@ sdk.optimize_deployment(
|
|
|
504
497
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
505
498
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
506
499
|
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
507
|
-
max_metric_calls=None, # budget: the metric-call ceiling for
|
|
500
|
+
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
508
501
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
509
502
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
510
|
-
|
|
511
|
-
patience=2, # optional: stop after this many steps without improvement
|
|
512
|
-
seed=0, # optional: the starting seed, advanced each step
|
|
503
|
+
seed=0, # optional: the search's random seed
|
|
513
504
|
poll_interval=3.0, # optional: seconds between status checks
|
|
514
|
-
timeout=600.0, # optional: seconds to wait for
|
|
505
|
+
timeout=600.0, # optional: seconds to wait for the run
|
|
515
506
|
)
|
|
516
507
|
```
|
|
517
508
|
|
|
@@ -523,6 +514,21 @@ budget is missing.
|
|
|
523
514
|
initiation with a 4xx, such as a 409 for missing data or a metric mismatch. It
|
|
524
515
|
raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
|
|
525
516
|
|
|
517
|
+
The result's `optimization_run_id` names the run that produced it.
|
|
518
|
+
`continue_optimization()` starts a new run from one of that run's candidates,
|
|
519
|
+
reusing its data, with a budget of its own:
|
|
520
|
+
|
|
521
|
+
```python
|
|
522
|
+
better = sdk.continue_optimization(best, max_metric_calls=120) # from the best candidate
|
|
523
|
+
|
|
524
|
+
for candidate in sdk.list_candidates(best.optimization_run_id): # read each one first
|
|
525
|
+
print(candidate["candidate_id"], candidate["aggregate_score"], candidate["instructions"])
|
|
526
|
+
other = sdk.continue_optimization(best, candidate="ca_...", auto="light")
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
530
|
+
`not_completed` or `unknown_candidate`.
|
|
531
|
+
|
|
526
532
|
## Command line
|
|
527
533
|
|
|
528
534
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -531,7 +537,7 @@ describes one:
|
|
|
531
537
|
|
|
532
538
|
```
|
|
533
539
|
usage: cmpnd [-h] [--version] [--api-key API_KEY] [--endpoint ENDPOINT]
|
|
534
|
-
{auth,login,logout,org,credentials,tool-servers,optimizations,programs,
|
|
540
|
+
{auth,login,logout,org,credentials,tool-servers,optimizations,programs,traces,evals,datasets,deployments,ps,status,logs,inspect,schema,sample,run,deploy,optimize}
|
|
535
541
|
...
|
|
536
542
|
|
|
537
543
|
CMPND platform CLI — deploy, run, and inspect DSPy programs.
|
|
@@ -625,7 +631,8 @@ captured input and output size limits, 65,536 bytes each by default.
|
|
|
625
631
|
|
|
626
632
|
### `cmpnd.auto_instrument()`
|
|
627
633
|
|
|
628
|
-
Registers the callback with DSPy, so every DSPy call records a trace.
|
|
634
|
+
Registers the callback with DSPy, so every DSPy call records a trace. The
|
|
635
|
+
traces carry no program and land in Unattributed.
|
|
629
636
|
|
|
630
637
|
### `cmpnd.Client()`
|
|
631
638
|
|
|
@@ -645,6 +652,11 @@ global config. Use it as a context manager or as a plain object.
|
|
|
645
652
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
646
653
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
647
654
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
655
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
656
|
+
`ca_` id, score, parent and instructions.
|
|
657
|
+
- `continue_optimization(run, candidate=None, ...)` runs a new optimization
|
|
658
|
+
from one candidate of a completed run, with that run's data and a new budget,
|
|
659
|
+
and returns its best `DeployedProgram`.
|
|
648
660
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
649
661
|
client's credentials. They flush the client's traces first.
|
|
650
662
|
- `close()` flushes the client's traces and closes the client. A closed
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# cmpnd
|
|
2
2
|
|
|
3
|
-
The `cmpnd` package traces
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The `cmpnd` package traces, deploys and optimizes DSPy programs on the cmpnd
|
|
4
|
+
platform. You give a program a name, and a client records its traces,
|
|
5
|
+
deployments and optimization runs under that name.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -15,46 +15,15 @@ uv add cmpnd # or: pip install cmpnd
|
|
|
15
15
|
The `cmpnd` library works with the cmpnd service at
|
|
16
16
|
[platform.cmpnd.ai](https://platform.cmpnd.ai). Create an API key on the
|
|
17
17
|
platform under Settings → API keys, and pass it as `api_key=` to
|
|
18
|
-
`cmpnd.
|
|
18
|
+
`cmpnd.Client()` or `cmpnd.configure()`. For a self-hosted cmpnd install, also
|
|
19
19
|
pass the install's URL as `endpoint=`.
|
|
20
20
|
|
|
21
21
|
## Quick start
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```python
|
|
28
|
-
import cmpnd
|
|
29
|
-
import dspy
|
|
30
|
-
|
|
31
|
-
cmpnd.configure(api_key="ck_xxx", project_tags="my-project")
|
|
32
|
-
cmpnd.auto_instrument()
|
|
33
|
-
|
|
34
|
-
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
|
|
35
|
-
|
|
36
|
-
cot = dspy.ChainOfThought("question -> answer")
|
|
37
|
-
result = cot(question="What is DSPy?") # the trace goes to cmpnd
|
|
38
|
-
|
|
39
|
-
cmpnd.trace_id(result) # "a1b2c3d4-...", or None outside instrumentation
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
`cmpnd.trace_id()` links a result to its platform trace, for example to attach
|
|
43
|
-
feedback later. Traces recorded this way have no program name. The platform
|
|
44
|
-
groups them by the structure of the program's modules. The API reference
|
|
45
|
-
below lists the other options of `cmpnd.configure()`.
|
|
46
|
-
|
|
47
|
-
## Program names
|
|
48
|
-
|
|
49
|
-
When you’re ready to name programs, evolve them, and share them with your team, switch
|
|
50
|
-
to `cmpnd.Client`. A client replaces `configure()` and `auto_instrument()` and offers
|
|
51
|
-
more features. A client records only the programs you run through it, and each of
|
|
52
|
-
those programs has a program name. A client takes most of the same arguments as `configure()`.
|
|
53
|
-
|
|
54
|
-
A program name is the name your organization gives a program, such as `question-answerer`.
|
|
55
|
-
Traces, deployments and optimization runs under one program name go to one
|
|
56
|
-
program. The platform makes the program the first time your organization uses
|
|
57
|
-
the program name.
|
|
23
|
+
A program name is the name your organization gives a program, such as
|
|
24
|
+
`question-answerer`. Traces, deployments and optimization runs under one
|
|
25
|
+
program name go to one program. The platform makes the program the first time
|
|
26
|
+
your organization uses the program name.
|
|
58
27
|
|
|
59
28
|
`@cmpnd.program(name)` above a `dspy.Module` class gives the class a program
|
|
60
29
|
name. Building the class takes its own arguments and a required `lm=`. The
|
|
@@ -77,17 +46,23 @@ class QA(dspy.Predict):
|
|
|
77
46
|
qa1 = QA(lm=dspy.LM("openai/gpt-6-luna"))
|
|
78
47
|
```
|
|
79
48
|
|
|
80
|
-
A
|
|
49
|
+
A `cmpnd.Client` runs the program and records its trace under the program
|
|
50
|
+
name:
|
|
81
51
|
|
|
82
52
|
```python
|
|
83
53
|
gepa = dspy.GEPA(metric=metric, reflection_lm=dspy.LM("openai/gpt-6-luna"), auto="light")
|
|
84
54
|
|
|
85
55
|
with cmpnd.Client(api_key="ck_xxx", project_tags="my-project") as sdk:
|
|
86
|
-
# the trace
|
|
56
|
+
# the trace goes to the program "question-answerer"
|
|
87
57
|
result = sdk.run_program(qa1, question="What is DSPy?")
|
|
88
58
|
qa2 = sdk.optimize_program(qa1, gepa, trainset=train, valset=val)
|
|
59
|
+
|
|
60
|
+
cmpnd.trace_id(result) # "a1b2c3d4-...", the trace of this run
|
|
89
61
|
```
|
|
90
62
|
|
|
63
|
+
`cmpnd.trace_id()` links a result to its platform trace, for example to attach
|
|
64
|
+
feedback later. A client records only the programs you run through it.
|
|
65
|
+
|
|
91
66
|
A client is active from construction. The `with` form flushes the client's
|
|
92
67
|
traces and closes it on exit. Without `with`, the client stays active until
|
|
93
68
|
you call `close()` or the process exits, and its traces go out at exit:
|
|
@@ -116,8 +91,26 @@ qa3 = cmpnd.Program(
|
|
|
116
91
|
- `optimize_program` runs the optimizer in your process and returns a copy of
|
|
117
92
|
the program that holds the optimized module. The copy keeps the program name
|
|
118
93
|
and the LM.
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
|
|
95
|
+
## Sketching with `auto_instrument()`
|
|
96
|
+
|
|
97
|
+
`cmpnd.auto_instrument()` records a trace of every DSPy call in the process,
|
|
98
|
+
with no other change to your code. Use it to sketch a
|
|
99
|
+
[DSPy program](https://dspy.ai/) and see what it does:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
cmpnd.configure(api_key="ck_xxx", project_tags="my-project")
|
|
103
|
+
cmpnd.auto_instrument()
|
|
104
|
+
|
|
105
|
+
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
|
|
106
|
+
dspy.ChainOfThought("question -> answer")(question="What is DSPy?")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
These traces carry no program, so the platform files them under Unattributed.
|
|
110
|
+
The first one in a process logs a warning that points to `@cmpnd.program` and
|
|
111
|
+
`cmpnd.Client`. Calling a `cmpnd.Program` directly while `auto_instrument()` is
|
|
112
|
+
on raises a `TypeError` that points to the client. The API reference below
|
|
113
|
+
lists the options of `cmpnd.configure()`.
|
|
121
114
|
|
|
122
115
|
## Deployed programs
|
|
123
116
|
|
|
@@ -453,14 +446,12 @@ sdk.optimize_deployment(
|
|
|
453
446
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
454
447
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
455
448
|
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
456
|
-
max_metric_calls=None, # budget: the metric-call ceiling for
|
|
449
|
+
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
457
450
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
458
451
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
459
|
-
|
|
460
|
-
patience=2, # optional: stop after this many steps without improvement
|
|
461
|
-
seed=0, # optional: the starting seed, advanced each step
|
|
452
|
+
seed=0, # optional: the search's random seed
|
|
462
453
|
poll_interval=3.0, # optional: seconds between status checks
|
|
463
|
-
timeout=600.0, # optional: seconds to wait for
|
|
454
|
+
timeout=600.0, # optional: seconds to wait for the run
|
|
464
455
|
)
|
|
465
456
|
```
|
|
466
457
|
|
|
@@ -472,6 +463,21 @@ budget is missing.
|
|
|
472
463
|
initiation with a 4xx, such as a 409 for missing data or a metric mismatch. It
|
|
473
464
|
raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
|
|
474
465
|
|
|
466
|
+
The result's `optimization_run_id` names the run that produced it.
|
|
467
|
+
`continue_optimization()` starts a new run from one of that run's candidates,
|
|
468
|
+
reusing its data, with a budget of its own:
|
|
469
|
+
|
|
470
|
+
```python
|
|
471
|
+
better = sdk.continue_optimization(best, max_metric_calls=120) # from the best candidate
|
|
472
|
+
|
|
473
|
+
for candidate in sdk.list_candidates(best.optimization_run_id): # read each one first
|
|
474
|
+
print(candidate["candidate_id"], candidate["aggregate_score"], candidate["instructions"])
|
|
475
|
+
other = sdk.continue_optimization(best, candidate="ca_...", auto="light")
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
A refusal raises `cmpnd.OptimizeError`, whose `error_code` says why, such as
|
|
479
|
+
`not_completed` or `unknown_candidate`.
|
|
480
|
+
|
|
475
481
|
## Command line
|
|
476
482
|
|
|
477
483
|
The package installs the `cmpnd` command. `cmpnd login` saves your API key for
|
|
@@ -480,7 +486,7 @@ describes one:
|
|
|
480
486
|
|
|
481
487
|
```
|
|
482
488
|
usage: cmpnd [-h] [--version] [--api-key API_KEY] [--endpoint ENDPOINT]
|
|
483
|
-
{auth,login,logout,org,credentials,tool-servers,optimizations,programs,
|
|
489
|
+
{auth,login,logout,org,credentials,tool-servers,optimizations,programs,traces,evals,datasets,deployments,ps,status,logs,inspect,schema,sample,run,deploy,optimize}
|
|
484
490
|
...
|
|
485
491
|
|
|
486
492
|
CMPND platform CLI — deploy, run, and inspect DSPy programs.
|
|
@@ -574,7 +580,8 @@ captured input and output size limits, 65,536 bytes each by default.
|
|
|
574
580
|
|
|
575
581
|
### `cmpnd.auto_instrument()`
|
|
576
582
|
|
|
577
|
-
Registers the callback with DSPy, so every DSPy call records a trace.
|
|
583
|
+
Registers the callback with DSPy, so every DSPy call records a trace. The
|
|
584
|
+
traces carry no program and land in Unattributed.
|
|
578
585
|
|
|
579
586
|
### `cmpnd.Client()`
|
|
580
587
|
|
|
@@ -594,6 +601,11 @@ global config. Use it as a context manager or as a plain object.
|
|
|
594
601
|
- `optimize_deployment(deployment, ...)` optimizes a deployment on the platform
|
|
595
602
|
and returns the best `DeployedProgram`, whose `.score` is the best score
|
|
596
603
|
found. It raises `cmpnd.OptimizeError` or `cmpnd.OptimizeFailed` on failure.
|
|
604
|
+
- `list_candidates(run_id)` returns a run's candidates as dicts, each with its
|
|
605
|
+
`ca_` id, score, parent and instructions.
|
|
606
|
+
- `continue_optimization(run, candidate=None, ...)` runs a new optimization
|
|
607
|
+
from one candidate of a completed run, with that run's data and a new budget,
|
|
608
|
+
and returns its best `DeployedProgram`.
|
|
597
609
|
- `list_traces(**filters)` and `get_trace(trace_id)` read traces with the
|
|
598
610
|
client's credentials. They flush the client's traces first.
|
|
599
611
|
- `close()` flushes the client's traces and closes the client. A closed
|
|
@@ -13,7 +13,7 @@ import os
|
|
|
13
13
|
from collections.abc import Sequence
|
|
14
14
|
from typing import Any, Literal
|
|
15
15
|
|
|
16
|
-
from . import _http, configuration
|
|
16
|
+
from . import _http, configuration, programs
|
|
17
17
|
|
|
18
18
|
DEFAULT_ENDPOINT = "https://platform.cmpnd.ai"
|
|
19
19
|
|
|
@@ -58,22 +58,23 @@ def list(
|
|
|
58
58
|
) -> dict[str, Any]:
|
|
59
59
|
"""List assessments by program or by trace, newest first.
|
|
60
60
|
|
|
61
|
-
Pass exactly one of ``program`` (every assessment of that program
|
|
62
|
-
``trace_id`` (only that trace's assessments). Returns
|
|
61
|
+
Pass exactly one of ``program`` (every assessment of that program, named by its
|
|
62
|
+
name or ``p_`` id) or ``trace_id`` (only that trace's assessments). Returns
|
|
63
63
|
``{"assessments": [...], "total": N, "limit", "offset", "has_more"}``.
|
|
64
64
|
``limit`` (max rows) and ``offset`` (skip this many) page the full set — the
|
|
65
65
|
server clamps ``limit`` to at most 200.
|
|
66
66
|
"""
|
|
67
67
|
if program is not None and trace_id is not None:
|
|
68
68
|
raise ValueError("pass exactly one of program or trace_id")
|
|
69
|
+
client = _client(api_key, endpoint)
|
|
69
70
|
if trace_id is not None:
|
|
70
71
|
scope: dict[str, str] = {"trace_id": trace_id}
|
|
71
72
|
elif program is not None:
|
|
72
|
-
scope = {"program": program}
|
|
73
|
+
scope = {"program": programs.program_id_for(client, program)}
|
|
73
74
|
else:
|
|
74
75
|
raise ValueError("pass exactly one of program or trace_id")
|
|
75
76
|
params = {**scope, "limit": str(limit), "offset": str(offset)}
|
|
76
|
-
return
|
|
77
|
+
return client.get("/api/v1/assessments", params=params)
|
|
77
78
|
|
|
78
79
|
|
|
79
80
|
def get(assessment_id: str, *, api_key: str | None = None, endpoint: str | None = None) -> dict[str, Any]:
|
|
@@ -4,7 +4,7 @@ The implementation of ``list`` and ``show`` over the shared ``_http`` transport.
|
|
|
4
4
|
:class:`cmpnd.Client`'s ``list_traces`` / ``get_trace`` call these directly; the
|
|
5
5
|
deprecated :mod:`cmpnd.traces` shim wraps them with a warning. The filter and
|
|
6
6
|
verb names match the ``cmpnd traces`` CLI vocabulary — ``list`` filtered by
|
|
7
|
-
``query`` / ``program`` / ``module`` / ``
|
|
7
|
+
``query`` / ``program`` / ``module`` / ``deployment`` / ``since`` / ``until`` /
|
|
8
8
|
``all_history``, and ``show`` for one trace — so the surfaces do not drift.
|
|
9
9
|
"""
|
|
10
10
|
|
|
@@ -29,7 +29,6 @@ def list(
|
|
|
29
29
|
model: str | None = None,
|
|
30
30
|
program: str | None = None,
|
|
31
31
|
module: str | None = None,
|
|
32
|
-
hash: str | None = None,
|
|
33
32
|
deployment: str | None = None,
|
|
34
33
|
metadata: dict[str, str] | None = None,
|
|
35
34
|
tags: list[str] | None = None,
|
|
@@ -49,11 +48,10 @@ def list(
|
|
|
49
48
|
``ignored_fields`` naming any request field an older server did not understand.
|
|
50
49
|
|
|
51
50
|
The filters mirror ``cmpnd traces list``: ``query`` searches indexed span text;
|
|
52
|
-
``program`` names the program by name
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
``since``;
|
|
51
|
+
``program`` names the program by its name or its program id (``p_…``);
|
|
52
|
+
``module`` is the root module's class, matched exactly. No index serves the
|
|
53
|
+
class, so without ``program`` it reads every trace in the time range and slows
|
|
54
|
+
as the range grows. Pair it with a program or a shorter ``since``;
|
|
57
55
|
``deployment`` is a deployment id; ``metadata`` is matched by containment (every
|
|
58
56
|
pair must be present); ``tags`` matches any of the given tags. ``since`` /
|
|
59
57
|
``until`` accept an ISO 8601 timestamp, a bare date (``YYYY-MM-DD``), or a
|
|
@@ -71,15 +69,14 @@ def list(
|
|
|
71
69
|
("status", status),
|
|
72
70
|
("q", query),
|
|
73
71
|
("model", model),
|
|
74
|
-
("program_name", program),
|
|
75
72
|
("module_class", module),
|
|
76
73
|
("deployment_id", deployment),
|
|
77
74
|
("tags", tags),
|
|
78
75
|
):
|
|
79
76
|
if val is not None:
|
|
80
77
|
body[wire_key] = val
|
|
81
|
-
if
|
|
82
|
-
body.update(program_filter(
|
|
78
|
+
if program is not None:
|
|
79
|
+
body.update(program_filter(program))
|
|
83
80
|
if metadata is not None:
|
|
84
81
|
body["metadata"] = dict(metadata)
|
|
85
82
|
if since is not None:
|
|
@@ -92,14 +89,14 @@ def list(
|
|
|
92
89
|
def program_filter(value: str) -> dict[str, str]:
|
|
93
90
|
"""The search-body key for one program filter value.
|
|
94
91
|
|
|
95
|
-
A program id (``p_…``) goes in ``program_id`` and
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
A program id (``p_…``) goes in ``program_id`` and anything else is a program
|
|
93
|
+
name, since no name starts with ``p_``. One helper for the CLI and the SDK,
|
|
94
|
+
so the two cannot split.
|
|
98
95
|
"""
|
|
99
96
|
text = value.strip()
|
|
100
97
|
if identity.is_program_id(text):
|
|
101
98
|
return {"program_id": text}
|
|
102
|
-
return {"
|
|
99
|
+
return {"program_name": value}
|
|
103
100
|
|
|
104
101
|
|
|
105
102
|
def show(trace_id: str, *, api_key: str | None = None, endpoint: str | None = None) -> dict[str, Any]:
|
|
@@ -15,7 +15,7 @@ import datetime
|
|
|
15
15
|
import os
|
|
16
16
|
from typing import Any
|
|
17
17
|
|
|
18
|
-
from . import _http, configuration
|
|
18
|
+
from . import _http, configuration, programs
|
|
19
19
|
|
|
20
20
|
DEFAULT_ENDPOINT = "https://platform.cmpnd.ai"
|
|
21
21
|
|
|
@@ -30,22 +30,24 @@ def default_name() -> str:
|
|
|
30
30
|
def create(
|
|
31
31
|
program: str, *, name: str | None = None, api_key: str | None = None, endpoint: str | None = None
|
|
32
32
|
) -> dict[str, Any]:
|
|
33
|
-
"""Create a
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
"""Create a valset owned by ``program``, a program name or ``p_`` id. ``name`` is auto-assigned when omitted."""
|
|
34
|
+
client = _client(api_key, endpoint)
|
|
35
|
+
payload = {"program": programs.program_id_for(client, program), "name": name or default_name()}
|
|
36
|
+
return client.post("/api/v1/valsets", json=payload)
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def list(
|
|
39
40
|
program: str, *, limit: int = 50, offset: int = 0, api_key: str | None = None, endpoint: str | None = None
|
|
40
41
|
) -> dict[str, Any]:
|
|
41
|
-
"""List a program
|
|
42
|
+
"""List the valsets of ``program``, a program name or ``p_`` id, newest first.
|
|
42
43
|
|
|
43
44
|
Returns ``{"valsets": [...], "total": N, "limit", "offset", "has_more"}``.
|
|
44
45
|
``limit`` / ``offset`` page the full set — the server clamps ``limit`` to at
|
|
45
46
|
most 200.
|
|
46
47
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
client = _client(api_key, endpoint)
|
|
49
|
+
params = {"program": programs.program_id_for(client, program), "limit": str(limit), "offset": str(offset)}
|
|
50
|
+
return client.get("/api/v1/valsets", params=params)
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
def get(valset_id: str, *, api_key: str | None = None, endpoint: str | None = None) -> dict[str, Any]:
|
|
@@ -39,6 +39,27 @@ def _declared_program_name() -> str | None:
|
|
|
39
39
|
return name if isinstance(name, str) else None
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
# Set once the process has warned that a trace names no program, so the warning
|
|
43
|
+
# appears once per process, whichever callback records the trace.
|
|
44
|
+
_warned_unattributed = False
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _warn_once_if_unattributed(trace: models.TraceBuilder) -> None:
|
|
48
|
+
"""Warn the first time a trace in this process names neither a program name nor a program id.
|
|
49
|
+
|
|
50
|
+
Such a trace belongs to no program, and the platform files it under Unattributed.
|
|
51
|
+
"""
|
|
52
|
+
global _warned_unattributed
|
|
53
|
+
if _warned_unattributed or trace.declared_name is not None or trace.program_id is not None:
|
|
54
|
+
return
|
|
55
|
+
_warned_unattributed = True
|
|
56
|
+
logger.warning(
|
|
57
|
+
"cmpnd: this trace names no program, so the platform files it under Unattributed. Give the program a "
|
|
58
|
+
"name with @cmpnd.program(name) and run it through cmpnd.Client, and its traces go to that program. "
|
|
59
|
+
"This warning appears once per process."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
42
63
|
def trace_id(prediction: Any) -> str | None:
|
|
43
64
|
"""Return the cmpnd trace id for a prediction returned by an instrumented program.
|
|
44
65
|
|
|
@@ -1193,6 +1214,10 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1193
1214
|
module_class=instance.__class__.__name__,
|
|
1194
1215
|
)
|
|
1195
1216
|
self._stamp(trace)
|
|
1217
|
+
# A root module call is where a program runs, so it is where an unnamed one
|
|
1218
|
+
# is caught. GEPA's own LM calls (_emit_optimization_lm_trace) belong to the
|
|
1219
|
+
# optimization run, which names the program, so they never warn.
|
|
1220
|
+
_warn_once_if_unattributed(trace)
|
|
1196
1221
|
|
|
1197
1222
|
# Attach the run ids this trace starts under, from this callback's own
|
|
1198
1223
|
# state right now — not at finalize (on_module_end), where the
|
|
@@ -24,7 +24,6 @@ from .commands import (
|
|
|
24
24
|
org,
|
|
25
25
|
programs,
|
|
26
26
|
provider_credentials,
|
|
27
|
-
signatures,
|
|
28
27
|
tool_servers,
|
|
29
28
|
top,
|
|
30
29
|
traces,
|
|
@@ -164,7 +163,6 @@ def main() -> None:
|
|
|
164
163
|
# gates each read on scope, so a caller without it gets a 403, not a
|
|
165
164
|
# hidden command.
|
|
166
165
|
programs.register(subparsers)
|
|
167
|
-
signatures.register(subparsers)
|
|
168
166
|
traces.register(subparsers)
|
|
169
167
|
evals.register(subparsers)
|
|
170
168
|
datasets.register(subparsers)
|
|
@@ -56,7 +56,8 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
56
56
|
scope.add_argument(
|
|
57
57
|
"program",
|
|
58
58
|
nargs="?",
|
|
59
|
-
|
|
59
|
+
metavar="PROGRAM",
|
|
60
|
+
help="Program name or p_ id",
|
|
60
61
|
)
|
|
61
62
|
scope.add_argument("--trace", dest="trace_id", metavar="TRACE_ID", help="A single trace's assessments")
|
|
62
63
|
pagination.add_args(ls, with_page_aliases=False, default_limit=50)
|
|
@@ -88,7 +89,15 @@ def handle_create(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
88
89
|
|
|
89
90
|
|
|
90
91
|
def handle_list(client: api_client.ApiClient, args: Any) -> Any:
|
|
91
|
-
|
|
92
|
+
if args.trace_id:
|
|
93
|
+
scope = {"trace_id": args.trace_id}
|
|
94
|
+
else:
|
|
95
|
+
from . import programs
|
|
96
|
+
|
|
97
|
+
program_id, _ = programs.resolve(
|
|
98
|
+
client, args.program, old_server_remedy="Upgrade the server to name a program."
|
|
99
|
+
)
|
|
100
|
+
scope = {"program": program_id}
|
|
92
101
|
params = {**scope, **pagination.wire(args, "limit_offset", as_str=True)}
|
|
93
102
|
return client.get("/api/v1/assessments", params=params)
|
|
94
103
|
|
|
@@ -50,7 +50,7 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
50
50
|
# `evals compare` is deliberately absent. The route requires a
|
|
51
51
|
# `dataset_hash`, and no eval read returns one: neither the list nor the
|
|
52
52
|
# detail projection carries it, and nor does the compare response itself.
|
|
53
|
-
# The only surface that emits one is `
|
|
53
|
+
# The only surface that emits one is `programs evals`, so the command
|
|
54
54
|
# would ship with a required argument its own noun cannot produce. It goes
|
|
55
55
|
# in once the projection carries the hash.
|
|
56
56
|
|