cmpnd 0.82.0__tar.gz → 0.84.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.82.0 → cmpnd-0.84.0}/AGENTS.md +7 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/PKG-INFO +80 -27
- {cmpnd-0.82.0 → cmpnd-0.84.0}/README.md +79 -26
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/callback.py +116 -21
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/__init__.py +6 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/top.py +3 -3
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/configuration.py +3 -3
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/context.py +41 -2
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/models.py +130 -6
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/cli.md +24 -14
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/client.md +25 -13
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/custom-proposer.md +3 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/sdk-instrumentation.md +33 -8
- {cmpnd-0.82.0 → cmpnd-0.84.0}/examples/generalizing_proposer.py +3 -1
- cmpnd-0.84.0/examples/local_ollama.py +57 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/README.md +20 -3
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/bodies.py +14 -7
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/exporter_http.py +84 -47
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/program_names.py +4 -29
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/protocols.py +19 -1
- cmpnd-0.84.0/ingest/cmpnd_ingest/span_context.py +63 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/trace_facts.py +4 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/pyproject.toml +1 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/test-in-linux.sh +18 -4
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/rlm_shape.py +4 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/test_rlm_shape.py +3 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/span_reference_fixture.py +9 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_callback.py +6 -2
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_context.py +20 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_credential_kwargs.py +1 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_credential_selection.py +1 -1
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_exporter_program_names.py +7 -4
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_program_identity.py +2 -2
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_span_references.py +18 -0
- cmpnd-0.84.0/tests/test_span_submission.py +492 -0
- cmpnd-0.84.0/tests/test_span_submission_wire_contract.py +190 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/uv.lock +1 -1
- cmpnd-0.82.0/examples/local_ollama.py +0 -48
- {cmpnd-0.82.0 → cmpnd-0.84.0}/.gitignore +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/CLAUDE.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/client.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/program_naming.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/references.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/drain.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_client.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_eval.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_eval_program_id.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_execute.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_identity.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_integration.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_models.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_no_signature_hash_on_the_wire.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimization_phase_callback.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimization_program_names.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_program_naming.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_retry.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.82.0 → cmpnd-0.84.0}/tests/test_xxh64.py +0 -0
|
@@ -137,7 +137,13 @@ still install against the `dspy>=…` floor in `dependencies`.
|
|
|
137
137
|
- `scripts/install-test-env.sh <python> <dspy>` builds `.venv` from one group's
|
|
138
138
|
locked tree, as each `sdk-test` leg in `ci-sdk.yml` does. From the repo root,
|
|
139
139
|
run `just sdk-test-env 3.13 3.3.0`, then, from `python-sdk/`,
|
|
140
|
-
`.venv/bin/python -m pytest tests/ -k "not e2e"`.
|
|
140
|
+
`.venv/bin/python -m pytest tests/ -k "not e2e"`. The root recipe
|
|
141
|
+
`SDK_TEST_PYTHON_VERSION=3.13 SDK_TEST_DSPY_VERSION=3.4.0 just sdk-test-linux`
|
|
142
|
+
runs the same locked environment in Linux. `SDK_TEST_LINUX_IMAGE` selects a
|
|
143
|
+
pinned CI builder when reproducing a job. The helper copies the worker pins
|
|
144
|
+
and truncation vectors and mounts Git metadata read-only for revision tests.
|
|
145
|
+
The revision tests require Git, which the CI builder provides.
|
|
146
|
+
`uv sync --extra dev` in
|
|
141
147
|
`python-sdk/` returns to the default group.
|
|
142
148
|
- `--latest` resolves every package fresh, as a user's install today would.
|
|
143
149
|
With the DSPy version `newest` it pins no DSPy either. The daily
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cmpnd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.84.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>
|
|
@@ -66,8 +66,13 @@ 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.Client()` or `cmpnd.configure()`. For a
|
|
70
|
-
pass the install's URL as `endpoint
|
|
69
|
+
`cmpnd.Client()` or `cmpnd.configure()`, or set `CMPND_API_KEY`. For a
|
|
70
|
+
self-hosted cmpnd install, also pass the install's URL as `endpoint=`, or set
|
|
71
|
+
`CMPND_ENDPOINT`.
|
|
72
|
+
|
|
73
|
+
The library reads its key and endpoint from those arguments and variables
|
|
74
|
+
alone. It never reads the key that `cmpnd login` stores for the command line,
|
|
75
|
+
so a script that runs after `cmpnd login` still sets `CMPND_API_KEY`.
|
|
71
76
|
|
|
72
77
|
## Quick start
|
|
73
78
|
|
|
@@ -176,12 +181,13 @@ client for server-side execution:
|
|
|
176
181
|
import cmpnd
|
|
177
182
|
import dspy
|
|
178
183
|
|
|
179
|
-
sdk = cmpnd.Client(
|
|
184
|
+
sdk = cmpnd.Client() # reads CMPND_API_KEY
|
|
185
|
+
openai = cmpnd.credentials.get("openai") # a credential your organization sealed
|
|
180
186
|
|
|
181
187
|
qa4 = cmpnd.Program(
|
|
182
188
|
"question-answerer", module=dspy.Predict("question -> answer"), lm=dspy.LM("openai/gpt-6-luna")
|
|
183
189
|
)
|
|
184
|
-
deployed = sdk.deploy_program(qa4)
|
|
190
|
+
deployed = sdk.deploy_program(qa4, credential=openai)
|
|
185
191
|
|
|
186
192
|
result = sdk.run_deployment(deployed, question="What is DSPy?") # runs server-side
|
|
187
193
|
print(result.answer)
|
|
@@ -219,13 +225,18 @@ deployed = sdk.deploy_program(program, credential=luna)
|
|
|
219
225
|
the organization does not hold raises `cmpnd.CredentialNotFound`, which lists
|
|
220
226
|
the names it does hold and the nearest one. `cmpnd.credentials.list()`
|
|
221
227
|
returns them all.
|
|
228
|
+
- `cmpnd.credentials.get` reads the key and endpoint the way
|
|
229
|
+
`cmpnd.configure()` does, and also takes `api_key=` and `endpoint=`.
|
|
222
230
|
- `credential=` takes a `cmpnd.Credential`, never a string. A string raises
|
|
223
231
|
and shows the `cmpnd.credentials.get(...)` line to write.
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
232
|
+
- An organization may have no default credential. Then every deploy and every
|
|
233
|
+
optimization names its credential. The platform refuses one that names none,
|
|
234
|
+
and the refusal lists the names the organization holds. An owner sets a
|
|
235
|
+
default with `cmpnd credentials default NAME`, and a deploy without
|
|
236
|
+
`credential=` spends it.
|
|
237
|
+
- The deployment records the credential's name. Its runs spend the newest
|
|
238
|
+
credential sealed under that name, so `run_deployment()` takes no credential,
|
|
239
|
+
and an owner who rotates a key needs no redeploy.
|
|
229
240
|
- The deploy prints the protocol, model and credential of each binding, as
|
|
230
241
|
above. A server that prints none chose the credential from the model's
|
|
231
242
|
provider prefix, and the SDK warns.
|
|
@@ -237,6 +248,24 @@ the platform only through `cmpnd credentials create`. `cmpnd deploy FILE`
|
|
|
237
248
|
refuses source whose import builds an LM carrying a key, and names the module,
|
|
238
249
|
the model and the field.
|
|
239
250
|
|
|
251
|
+
### Gateways
|
|
252
|
+
|
|
253
|
+
An OpenAI-compatible gateway, such as LunaRoute, is a credential of its own.
|
|
254
|
+
Seal its key with the gateway's preset, or with `--preset openai_like` and the
|
|
255
|
+
gateway's address:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
cmpnd credentials create --name luna-exec --preset lunaroute < key.txt
|
|
259
|
+
cmpnd credentials create --name my-gateway --preset openai_like --api-base https://gateway.example.com/v1 < key.txt
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Spell the gateway's models `openai/<model>`, such as
|
|
263
|
+
`openai/deepseek-4.1-flash`, and deploy with
|
|
264
|
+
`credential=cmpnd.credentials.get("luna-exec")`. The `openai/` prefix selects
|
|
265
|
+
the Chat Completions wire protocol, and the gateway receives the model after
|
|
266
|
+
the first `/`. The credential decides the address and the key, so one gateway
|
|
267
|
+
serves every model it routes.
|
|
268
|
+
|
|
240
269
|
### The same source on your laptop and hosted
|
|
241
270
|
|
|
242
271
|
A program's logic runs unchanged on your laptop and hosted. On your laptop it
|
|
@@ -259,11 +288,10 @@ def metric(gold, pred, trace=None, pred_name=None, pred_trace=None, lms=None):
|
|
|
259
288
|
return dspy.Prediction(score=float(verdict.correct), feedback="correct" if verdict.correct else "wrong")
|
|
260
289
|
```
|
|
261
290
|
|
|
262
|
-
Seal the key once for the organization
|
|
291
|
+
Seal the key once for the organization:
|
|
263
292
|
|
|
264
293
|
```bash
|
|
265
294
|
printf '%s' "$OPENAI_API_KEY" | cmpnd credentials create --name openai --preset openai
|
|
266
|
-
cmpnd credentials default openai
|
|
267
295
|
```
|
|
268
296
|
|
|
269
297
|
The entry point is the only code that knows where the run happens:
|
|
@@ -287,13 +315,15 @@ lms = {"critic": dspy.LM("openai/gpt-5-mini")}
|
|
|
287
315
|
train, val = load_examples() # your dspy.Example lists
|
|
288
316
|
|
|
289
317
|
if HOSTED:
|
|
290
|
-
|
|
318
|
+
openai = cmpnd.credentials.get("openai")
|
|
319
|
+
deployed = sdk.deploy_program(qa, credential=openai)
|
|
291
320
|
print(sdk.run_deployment(deployed, question="What is DSPy?"))
|
|
292
321
|
best = sdk.optimize_deployment(
|
|
293
322
|
deployed,
|
|
294
323
|
trainset=train,
|
|
295
324
|
valset=val,
|
|
296
325
|
metric=metric, # the platform hands it lms
|
|
326
|
+
credential=openai, # every model below spends it
|
|
297
327
|
reflection_lm=cmpnd.HostedLM(reflection),
|
|
298
328
|
lms={name: cmpnd.HostedLM(model) for name, model in lms.items()},
|
|
299
329
|
auto="light",
|
|
@@ -305,12 +335,12 @@ else:
|
|
|
305
335
|
```
|
|
306
336
|
|
|
307
337
|
`python main.py` runs everything on your laptop, and `python main.py --hosted`
|
|
308
|
-
runs it on the platform. `cmpnd deploy qa.py qa` deploys
|
|
309
|
-
terminal.
|
|
338
|
+
runs it on the platform. `cmpnd deploy qa.py qa --credential openai` deploys
|
|
339
|
+
the same file from the terminal.
|
|
310
340
|
|
|
311
341
|
| | On your laptop | Hosted |
|
|
312
342
|
|---|---|---|
|
|
313
|
-
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default |
|
|
343
|
+
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default, if one is set |
|
|
314
344
|
| Address | the LM's `api_base`, else the provider's endpoint | the credential's `api_base` |
|
|
315
345
|
| Model | `gpt-5-mini`, the model after its first `/` | `gpt-5-mini` |
|
|
316
346
|
| The metric's `lms` | the dict the entry point binds | the run's `lms=`, which the platform hands it |
|
|
@@ -348,7 +378,7 @@ sdk.deploy_program(
|
|
|
348
378
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
349
379
|
timeout=300, # optional: seconds to wait for the deployment to be ready
|
|
350
380
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
351
|
-
credential=None, #
|
|
381
|
+
credential=None, # a cmpnd.Credential the program's model spends, else the org's default, if one is set
|
|
352
382
|
)
|
|
353
383
|
```
|
|
354
384
|
|
|
@@ -371,12 +401,13 @@ found. Deploy the program first:
|
|
|
371
401
|
import cmpnd
|
|
372
402
|
import dspy
|
|
373
403
|
|
|
374
|
-
sdk = cmpnd.Client(
|
|
404
|
+
sdk = cmpnd.Client() # reads CMPND_API_KEY
|
|
405
|
+
openai = cmpnd.credentials.get("openai")
|
|
375
406
|
|
|
376
407
|
program = cmpnd.Program(
|
|
377
408
|
"haiku", module=dspy.ChainOfThought("topic -> haiku"), lm=dspy.LM("openai/gpt-6-luna")
|
|
378
409
|
)
|
|
379
|
-
deployed = sdk.deploy_program(program)
|
|
410
|
+
deployed = sdk.deploy_program(program, credential=openai)
|
|
380
411
|
|
|
381
412
|
# GEPA needs a five-argument feedback metric that returns dspy.Prediction(score=, feedback=)
|
|
382
413
|
def metric(example, pred, trace=None, pred_name=None, pred_trace=None):
|
|
@@ -391,6 +422,7 @@ best = sdk.optimize_deployment(
|
|
|
391
422
|
trainset=train,
|
|
392
423
|
valset=val,
|
|
393
424
|
metric=metric,
|
|
425
|
+
credential=openai,
|
|
394
426
|
reflection_lm=dspy.LM("openai/gpt-6-luna"),
|
|
395
427
|
auto="light",
|
|
396
428
|
)
|
|
@@ -429,9 +461,9 @@ best = sdk.optimize_deployment(
|
|
|
429
461
|
|
|
430
462
|
`cmpnd.HostedLM(lm, credential=c)` wraps a chat LM, and
|
|
431
463
|
`cmpnd.SystemOne(model, credential=c)` declares a System One model. A binding
|
|
432
|
-
without a credential spends the run's,
|
|
433
|
-
platform refuses a credential whose endpoint does not serve a
|
|
434
|
-
protocol, and names the `credential=` to add.
|
|
464
|
+
without a credential spends the run's, else the organization's default, if one
|
|
465
|
+
is set. The platform refuses a credential whose endpoint does not serve a
|
|
466
|
+
binding's protocol, and names the `credential=` to add.
|
|
435
467
|
|
|
436
468
|
The SDK checks the metric before any network call. GEPA writes each new
|
|
437
469
|
instruction from the textual feedback the metric returns, so it needs a
|
|
@@ -466,6 +498,7 @@ def faithfulness(gold, pred, trace, pred_name, pred_trace, lms=None):
|
|
|
466
498
|
|
|
467
499
|
best = sdk.optimize_deployment(
|
|
468
500
|
deployed, optimizer="gepa", trainset=train, valset=val, metric=faithfulness,
|
|
501
|
+
credential=openai,
|
|
469
502
|
reflection_lm=dspy.LM("openai/gpt-6-luna"),
|
|
470
503
|
lms={"critic": dspy.LM("openai/gpt-6-luna")},
|
|
471
504
|
max_metric_calls=300,
|
|
@@ -499,7 +532,7 @@ sdk.optimize_deployment(
|
|
|
499
532
|
config=None, # optional: optimizer config, allow-listed by the platform
|
|
500
533
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
501
534
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
502
|
-
credential=None, #
|
|
535
|
+
credential=None, # the cmpnd.Credential every other binding spends, else the org's default, if one is set
|
|
503
536
|
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
504
537
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
505
538
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
@@ -565,13 +598,33 @@ Deploy a source file under a program name, or optimize the program a file
|
|
|
565
598
|
declares:
|
|
566
599
|
|
|
567
600
|
```bash
|
|
568
|
-
cmpnd deploy program.py question-answerer
|
|
569
|
-
cmpnd optimize gepa task.py haiku --reflection-model openai/gpt-6-luna --auto light
|
|
601
|
+
cmpnd deploy program.py question-answerer --credential openai
|
|
602
|
+
cmpnd optimize gepa task.py haiku --credential openai --reflection-model openai/gpt-6-luna --auto light
|
|
570
603
|
```
|
|
571
604
|
|
|
572
605
|
`cmpnd deploy` uploads the file as written. `cmpnd optimize` reads `program`,
|
|
573
606
|
`trainset`, `valset` and `metric` from the file, deploys the program under the
|
|
574
|
-
program name and prints the best deployment ID.
|
|
607
|
+
program name and prints the best deployment ID. `--credential` names the
|
|
608
|
+
credential the program's models spend, and `cmpnd credentials list` shows the
|
|
609
|
+
names your organization holds.
|
|
610
|
+
|
|
611
|
+
`cmpnd programs rename PROGRAM NAME` gives a program a new name, or names one
|
|
612
|
+
that has none. PROGRAM is a program name or a `p_` id, and the program keeps
|
|
613
|
+
its id and its history. The old name is free at once, so update the code that
|
|
614
|
+
declares it.
|
|
615
|
+
|
|
616
|
+
A program calls tools on an MCP server once your organization seals the
|
|
617
|
+
server's key, registers the server and allows its tools:
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
cmpnd credentials create --kind mcp --server https://mcp.exa.ai/mcp --name exa-prod \
|
|
621
|
+
--placement query_param --query-param-name exaApiKey < exa-key.txt
|
|
622
|
+
cmpnd tool-servers create --url https://mcp.exa.ai/mcp --credential exa-prod
|
|
623
|
+
cmpnd tool-servers allow <server_id> web_search_exa
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
[`docs/cli.md`](docs/cli.md) describes every command, including "Tool
|
|
627
|
+
servers".
|
|
575
628
|
|
|
576
629
|
## Custom spans
|
|
577
630
|
|
|
@@ -632,7 +685,7 @@ cmpnd.configure(
|
|
|
632
685
|
flush_interval_seconds=5.0, # optional: seconds between flushes
|
|
633
686
|
capture_inputs=True, # optional: record span inputs
|
|
634
687
|
capture_outputs=True, # optional: record span outputs
|
|
635
|
-
default_tags={"env": "prod"}, # optional: tags on every trace
|
|
688
|
+
default_tags={"env": "prod"}, # optional: tags on every trace; a run's own tags override them
|
|
636
689
|
)
|
|
637
690
|
```
|
|
638
691
|
|
|
@@ -15,8 +15,13 @@ 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.Client()` or `cmpnd.configure()`. For a
|
|
19
|
-
pass the install's URL as `endpoint
|
|
18
|
+
`cmpnd.Client()` or `cmpnd.configure()`, or set `CMPND_API_KEY`. For a
|
|
19
|
+
self-hosted cmpnd install, also pass the install's URL as `endpoint=`, or set
|
|
20
|
+
`CMPND_ENDPOINT`.
|
|
21
|
+
|
|
22
|
+
The library reads its key and endpoint from those arguments and variables
|
|
23
|
+
alone. It never reads the key that `cmpnd login` stores for the command line,
|
|
24
|
+
so a script that runs after `cmpnd login` still sets `CMPND_API_KEY`.
|
|
20
25
|
|
|
21
26
|
## Quick start
|
|
22
27
|
|
|
@@ -125,12 +130,13 @@ client for server-side execution:
|
|
|
125
130
|
import cmpnd
|
|
126
131
|
import dspy
|
|
127
132
|
|
|
128
|
-
sdk = cmpnd.Client(
|
|
133
|
+
sdk = cmpnd.Client() # reads CMPND_API_KEY
|
|
134
|
+
openai = cmpnd.credentials.get("openai") # a credential your organization sealed
|
|
129
135
|
|
|
130
136
|
qa4 = cmpnd.Program(
|
|
131
137
|
"question-answerer", module=dspy.Predict("question -> answer"), lm=dspy.LM("openai/gpt-6-luna")
|
|
132
138
|
)
|
|
133
|
-
deployed = sdk.deploy_program(qa4)
|
|
139
|
+
deployed = sdk.deploy_program(qa4, credential=openai)
|
|
134
140
|
|
|
135
141
|
result = sdk.run_deployment(deployed, question="What is DSPy?") # runs server-side
|
|
136
142
|
print(result.answer)
|
|
@@ -168,13 +174,18 @@ deployed = sdk.deploy_program(program, credential=luna)
|
|
|
168
174
|
the organization does not hold raises `cmpnd.CredentialNotFound`, which lists
|
|
169
175
|
the names it does hold and the nearest one. `cmpnd.credentials.list()`
|
|
170
176
|
returns them all.
|
|
177
|
+
- `cmpnd.credentials.get` reads the key and endpoint the way
|
|
178
|
+
`cmpnd.configure()` does, and also takes `api_key=` and `endpoint=`.
|
|
171
179
|
- `credential=` takes a `cmpnd.Credential`, never a string. A string raises
|
|
172
180
|
and shows the `cmpnd.credentials.get(...)` line to write.
|
|
173
|
-
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
- An organization may have no default credential. Then every deploy and every
|
|
182
|
+
optimization names its credential. The platform refuses one that names none,
|
|
183
|
+
and the refusal lists the names the organization holds. An owner sets a
|
|
184
|
+
default with `cmpnd credentials default NAME`, and a deploy without
|
|
185
|
+
`credential=` spends it.
|
|
186
|
+
- The deployment records the credential's name. Its runs spend the newest
|
|
187
|
+
credential sealed under that name, so `run_deployment()` takes no credential,
|
|
188
|
+
and an owner who rotates a key needs no redeploy.
|
|
178
189
|
- The deploy prints the protocol, model and credential of each binding, as
|
|
179
190
|
above. A server that prints none chose the credential from the model's
|
|
180
191
|
provider prefix, and the SDK warns.
|
|
@@ -186,6 +197,24 @@ the platform only through `cmpnd credentials create`. `cmpnd deploy FILE`
|
|
|
186
197
|
refuses source whose import builds an LM carrying a key, and names the module,
|
|
187
198
|
the model and the field.
|
|
188
199
|
|
|
200
|
+
### Gateways
|
|
201
|
+
|
|
202
|
+
An OpenAI-compatible gateway, such as LunaRoute, is a credential of its own.
|
|
203
|
+
Seal its key with the gateway's preset, or with `--preset openai_like` and the
|
|
204
|
+
gateway's address:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
cmpnd credentials create --name luna-exec --preset lunaroute < key.txt
|
|
208
|
+
cmpnd credentials create --name my-gateway --preset openai_like --api-base https://gateway.example.com/v1 < key.txt
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Spell the gateway's models `openai/<model>`, such as
|
|
212
|
+
`openai/deepseek-4.1-flash`, and deploy with
|
|
213
|
+
`credential=cmpnd.credentials.get("luna-exec")`. The `openai/` prefix selects
|
|
214
|
+
the Chat Completions wire protocol, and the gateway receives the model after
|
|
215
|
+
the first `/`. The credential decides the address and the key, so one gateway
|
|
216
|
+
serves every model it routes.
|
|
217
|
+
|
|
189
218
|
### The same source on your laptop and hosted
|
|
190
219
|
|
|
191
220
|
A program's logic runs unchanged on your laptop and hosted. On your laptop it
|
|
@@ -208,11 +237,10 @@ def metric(gold, pred, trace=None, pred_name=None, pred_trace=None, lms=None):
|
|
|
208
237
|
return dspy.Prediction(score=float(verdict.correct), feedback="correct" if verdict.correct else "wrong")
|
|
209
238
|
```
|
|
210
239
|
|
|
211
|
-
Seal the key once for the organization
|
|
240
|
+
Seal the key once for the organization:
|
|
212
241
|
|
|
213
242
|
```bash
|
|
214
243
|
printf '%s' "$OPENAI_API_KEY" | cmpnd credentials create --name openai --preset openai
|
|
215
|
-
cmpnd credentials default openai
|
|
216
244
|
```
|
|
217
245
|
|
|
218
246
|
The entry point is the only code that knows where the run happens:
|
|
@@ -236,13 +264,15 @@ lms = {"critic": dspy.LM("openai/gpt-5-mini")}
|
|
|
236
264
|
train, val = load_examples() # your dspy.Example lists
|
|
237
265
|
|
|
238
266
|
if HOSTED:
|
|
239
|
-
|
|
267
|
+
openai = cmpnd.credentials.get("openai")
|
|
268
|
+
deployed = sdk.deploy_program(qa, credential=openai)
|
|
240
269
|
print(sdk.run_deployment(deployed, question="What is DSPy?"))
|
|
241
270
|
best = sdk.optimize_deployment(
|
|
242
271
|
deployed,
|
|
243
272
|
trainset=train,
|
|
244
273
|
valset=val,
|
|
245
274
|
metric=metric, # the platform hands it lms
|
|
275
|
+
credential=openai, # every model below spends it
|
|
246
276
|
reflection_lm=cmpnd.HostedLM(reflection),
|
|
247
277
|
lms={name: cmpnd.HostedLM(model) for name, model in lms.items()},
|
|
248
278
|
auto="light",
|
|
@@ -254,12 +284,12 @@ else:
|
|
|
254
284
|
```
|
|
255
285
|
|
|
256
286
|
`python main.py` runs everything on your laptop, and `python main.py --hosted`
|
|
257
|
-
runs it on the platform. `cmpnd deploy qa.py qa` deploys
|
|
258
|
-
terminal.
|
|
287
|
+
runs it on the platform. `cmpnd deploy qa.py qa --credential openai` deploys
|
|
288
|
+
the same file from the terminal.
|
|
259
289
|
|
|
260
290
|
| | On your laptop | Hosted |
|
|
261
291
|
|---|---|---|
|
|
262
|
-
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default |
|
|
292
|
+
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default, if one is set |
|
|
263
293
|
| Address | the LM's `api_base`, else the provider's endpoint | the credential's `api_base` |
|
|
264
294
|
| Model | `gpt-5-mini`, the model after its first `/` | `gpt-5-mini` |
|
|
265
295
|
| The metric's `lms` | the dict the entry point binds | the run's `lms=`, which the platform hands it |
|
|
@@ -297,7 +327,7 @@ sdk.deploy_program(
|
|
|
297
327
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
298
328
|
timeout=300, # optional: seconds to wait for the deployment to be ready
|
|
299
329
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
300
|
-
credential=None, #
|
|
330
|
+
credential=None, # a cmpnd.Credential the program's model spends, else the org's default, if one is set
|
|
301
331
|
)
|
|
302
332
|
```
|
|
303
333
|
|
|
@@ -320,12 +350,13 @@ found. Deploy the program first:
|
|
|
320
350
|
import cmpnd
|
|
321
351
|
import dspy
|
|
322
352
|
|
|
323
|
-
sdk = cmpnd.Client(
|
|
353
|
+
sdk = cmpnd.Client() # reads CMPND_API_KEY
|
|
354
|
+
openai = cmpnd.credentials.get("openai")
|
|
324
355
|
|
|
325
356
|
program = cmpnd.Program(
|
|
326
357
|
"haiku", module=dspy.ChainOfThought("topic -> haiku"), lm=dspy.LM("openai/gpt-6-luna")
|
|
327
358
|
)
|
|
328
|
-
deployed = sdk.deploy_program(program)
|
|
359
|
+
deployed = sdk.deploy_program(program, credential=openai)
|
|
329
360
|
|
|
330
361
|
# GEPA needs a five-argument feedback metric that returns dspy.Prediction(score=, feedback=)
|
|
331
362
|
def metric(example, pred, trace=None, pred_name=None, pred_trace=None):
|
|
@@ -340,6 +371,7 @@ best = sdk.optimize_deployment(
|
|
|
340
371
|
trainset=train,
|
|
341
372
|
valset=val,
|
|
342
373
|
metric=metric,
|
|
374
|
+
credential=openai,
|
|
343
375
|
reflection_lm=dspy.LM("openai/gpt-6-luna"),
|
|
344
376
|
auto="light",
|
|
345
377
|
)
|
|
@@ -378,9 +410,9 @@ best = sdk.optimize_deployment(
|
|
|
378
410
|
|
|
379
411
|
`cmpnd.HostedLM(lm, credential=c)` wraps a chat LM, and
|
|
380
412
|
`cmpnd.SystemOne(model, credential=c)` declares a System One model. A binding
|
|
381
|
-
without a credential spends the run's,
|
|
382
|
-
platform refuses a credential whose endpoint does not serve a
|
|
383
|
-
protocol, and names the `credential=` to add.
|
|
413
|
+
without a credential spends the run's, else the organization's default, if one
|
|
414
|
+
is set. The platform refuses a credential whose endpoint does not serve a
|
|
415
|
+
binding's protocol, and names the `credential=` to add.
|
|
384
416
|
|
|
385
417
|
The SDK checks the metric before any network call. GEPA writes each new
|
|
386
418
|
instruction from the textual feedback the metric returns, so it needs a
|
|
@@ -415,6 +447,7 @@ def faithfulness(gold, pred, trace, pred_name, pred_trace, lms=None):
|
|
|
415
447
|
|
|
416
448
|
best = sdk.optimize_deployment(
|
|
417
449
|
deployed, optimizer="gepa", trainset=train, valset=val, metric=faithfulness,
|
|
450
|
+
credential=openai,
|
|
418
451
|
reflection_lm=dspy.LM("openai/gpt-6-luna"),
|
|
419
452
|
lms={"critic": dspy.LM("openai/gpt-6-luna")},
|
|
420
453
|
max_metric_calls=300,
|
|
@@ -448,7 +481,7 @@ sdk.optimize_deployment(
|
|
|
448
481
|
config=None, # optional: optimizer config, allow-listed by the platform
|
|
449
482
|
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
450
483
|
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
451
|
-
credential=None, #
|
|
484
|
+
credential=None, # the cmpnd.Credential every other binding spends, else the org's default, if one is set
|
|
452
485
|
max_metric_calls=None, # budget: the metric-call ceiling for the run
|
|
453
486
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
454
487
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
@@ -514,13 +547,33 @@ Deploy a source file under a program name, or optimize the program a file
|
|
|
514
547
|
declares:
|
|
515
548
|
|
|
516
549
|
```bash
|
|
517
|
-
cmpnd deploy program.py question-answerer
|
|
518
|
-
cmpnd optimize gepa task.py haiku --reflection-model openai/gpt-6-luna --auto light
|
|
550
|
+
cmpnd deploy program.py question-answerer --credential openai
|
|
551
|
+
cmpnd optimize gepa task.py haiku --credential openai --reflection-model openai/gpt-6-luna --auto light
|
|
519
552
|
```
|
|
520
553
|
|
|
521
554
|
`cmpnd deploy` uploads the file as written. `cmpnd optimize` reads `program`,
|
|
522
555
|
`trainset`, `valset` and `metric` from the file, deploys the program under the
|
|
523
|
-
program name and prints the best deployment ID.
|
|
556
|
+
program name and prints the best deployment ID. `--credential` names the
|
|
557
|
+
credential the program's models spend, and `cmpnd credentials list` shows the
|
|
558
|
+
names your organization holds.
|
|
559
|
+
|
|
560
|
+
`cmpnd programs rename PROGRAM NAME` gives a program a new name, or names one
|
|
561
|
+
that has none. PROGRAM is a program name or a `p_` id, and the program keeps
|
|
562
|
+
its id and its history. The old name is free at once, so update the code that
|
|
563
|
+
declares it.
|
|
564
|
+
|
|
565
|
+
A program calls tools on an MCP server once your organization seals the
|
|
566
|
+
server's key, registers the server and allows its tools:
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
cmpnd credentials create --kind mcp --server https://mcp.exa.ai/mcp --name exa-prod \
|
|
570
|
+
--placement query_param --query-param-name exaApiKey < exa-key.txt
|
|
571
|
+
cmpnd tool-servers create --url https://mcp.exa.ai/mcp --credential exa-prod
|
|
572
|
+
cmpnd tool-servers allow <server_id> web_search_exa
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
[`docs/cli.md`](docs/cli.md) describes every command, including "Tool
|
|
576
|
+
servers".
|
|
524
577
|
|
|
525
578
|
## Custom spans
|
|
526
579
|
|
|
@@ -581,7 +634,7 @@ cmpnd.configure(
|
|
|
581
634
|
flush_interval_seconds=5.0, # optional: seconds between flushes
|
|
582
635
|
capture_inputs=True, # optional: record span inputs
|
|
583
636
|
capture_outputs=True, # optional: record span outputs
|
|
584
|
-
default_tags={"env": "prod"}, # optional: tags on every trace
|
|
637
|
+
default_tags={"env": "prod"}, # optional: tags on every trace; a run's own tags override them
|
|
585
638
|
)
|
|
586
639
|
```
|
|
587
640
|
|