cmpnd 0.56.0__tar.gz → 0.58.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.56.0 → cmpnd-0.58.0}/AGENTS.md +34 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/PKG-INFO +174 -12
- {cmpnd-0.56.0 → cmpnd-0.58.0}/README.md +172 -10
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/__init__.py +8 -2
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_authored_import.py +113 -4
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_gepa_patch.py +6 -9
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/callback.py +4 -3
- cmpnd-0.58.0/cmpnd/cli/commands/provider_credentials.py +532 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/top.py +14 -1
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/verbs.py +2 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/client.py +54 -9
- cmpnd-0.58.0/cmpnd/credentials.py +199 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/deployment.py +105 -22
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/helpers.py +116 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/lm_configuration.py +71 -15
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimization.py +109 -53
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimizers/tracker.py +3 -5
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/cli.md +78 -25
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/sdk-instrumentation.md +13 -5
- {cmpnd-0.56.0 → cmpnd-0.58.0}/pyproject.toml +31 -4
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/capture_review_run.py +4 -1
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/check-pip-install.sh +1 -1
- cmpnd-0.58.0/scripts/install-test-env.sh +67 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/test-in-linux.sh +8 -7
- cmpnd-0.58.0/tests/_credential_route.py +96 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/committee_task.py +49 -54
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/helpers.py +93 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +3 -3
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/hosted_optimize_probe.py +51 -26
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/test_logs_renders_traces.py +2 -2
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/span_reference_fixture.py +13 -7
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/_provider.py +31 -24
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_deploy_programs.py +7 -4
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_optimize_loop.py +19 -18
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_optimize_loop_wasm.py +23 -50
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_optimize_stress.py +16 -18
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_provider_roles.py +65 -3
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_real_provider_twins.py +11 -9
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_rlm_wasm.py +8 -13
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_adapter_reentrancy.py +2 -8
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_authored_named_models.py +19 -5
- cmpnd-0.58.0/tests/test_cli/test_provider_credentials.py +660 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_top.py +31 -1
- cmpnd-0.58.0/tests/test_credential_kwargs.py +306 -0
- cmpnd-0.58.0/tests/test_credential_selection.py +320 -0
- cmpnd-0.58.0/tests/test_credential_values.py +193 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deploy.py +55 -84
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_lm_usage_shapes.py +2 -4
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_lms.py +29 -15
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_reflection_lm.py +18 -34
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_program_lineage_persist.py +4 -5
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_rlm_patch.py +19 -6
- cmpnd-0.58.0/tests/test_seal_lm_credential.py +153 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_span_references.py +3 -3
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_system_one.py +31 -12
- {cmpnd-0.56.0 → cmpnd-0.58.0}/uv.lock +421 -194
- cmpnd-0.56.0/cmpnd/cli/commands/provider_credentials.py +0 -321
- cmpnd-0.56.0/tests/test_cli/test_provider_credentials.py +0 -319
- {cmpnd-0.56.0 → cmpnd-0.58.0}/.gitignore +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/CLAUDE.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/signatures.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/context.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/models.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/references.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/client.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/README.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/release-stress.sh +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/drain.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/_readiness.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/_reliability.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/_result.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/mint_bedrock_token.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_multi_client_stress.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_optimize_client_committee.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_readiness.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_reliability.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_reliability_classify.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/stress/test_trace_search.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_authored.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_callback.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_signatures.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_client.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_context.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_eval.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_execute.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_integration.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_models.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_release_stress_script.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_retry.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.56.0 → cmpnd-0.58.0}/tests/test_xxh64.py +0 -0
|
@@ -123,6 +123,40 @@ parameter, and a spec-less mock accepts one anyway.
|
|
|
123
123
|
with real LLMs (`CMPND_E2E_*` keys). It never uses a mock or an in-process
|
|
124
124
|
fake, and it runs only locally.
|
|
125
125
|
|
|
126
|
+
## DSPy versions under test
|
|
127
|
+
|
|
128
|
+
The SDK supports DSPy 3.3.x and 3.4.x, and `dependencies` floors DSPy at
|
|
129
|
+
3.3.0. `pyproject.toml` declares one dependency group per DSPy version the
|
|
130
|
+
`sdk-test` matrix tests, such as `dspy-3-4-1 = ["dspy==3.4.1"]`.
|
|
131
|
+
`[tool.uv] conflicts` makes the groups mutually exclusive, so `uv.lock` holds a
|
|
132
|
+
whole tree for each DSPy. Dependency groups never reach the wheel, so users
|
|
133
|
+
still install against the `dspy>=…` floor in `dependencies`.
|
|
134
|
+
|
|
135
|
+
- A plain `uv sync` or `uv run` installs the default group, the newest tested
|
|
136
|
+
DSPy.
|
|
137
|
+
- `scripts/install-test-env.sh <python> <dspy>` builds `.venv` from one group's
|
|
138
|
+
locked tree, as each `sdk-test` leg in `ci-sdk.yml` does. From the repo root,
|
|
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"`. `uv sync --extra dev` in
|
|
141
|
+
`python-sdk/` returns to the default group.
|
|
142
|
+
- `--latest` resolves every package fresh, as a user's install today would.
|
|
143
|
+
With the DSPy version `newest` it pins no DSPy either. The daily
|
|
144
|
+
`sdk-latest-dependencies.yml` run uses both: every sdk-test leg, plus one
|
|
145
|
+
leg on the newest DSPy, which is the first to see a DSPy release no group
|
|
146
|
+
tests yet. A failure there alerts Slack.
|
|
147
|
+
- A DSPy release can pin some packages exactly, such as gepa (`dspy==3.3.0`
|
|
148
|
+
pins gepa 0.1.1). Its group locks those packages at the pinned versions. The
|
|
149
|
+
`mcp` extra floors DSPy at 3.3.1, so it conflicts with the `dspy-3-3-0`
|
|
150
|
+
group.
|
|
151
|
+
|
|
152
|
+
To test another DSPy version, add its group to `[dependency-groups]` and to
|
|
153
|
+
the first `conflicts` list, add a conflict with the `mcp` extra if it is below
|
|
154
|
+
3.3.1, add the leg to `sdk-test`'s matrix and to
|
|
155
|
+
`sdk-latest-dependencies.yml`, and run `uv lock`.
|
|
156
|
+
`.github/scripts/test_workflows.py` fails while the groups and the matrix
|
|
157
|
+
disagree. To move the default, change `default-groups` and refresh the span
|
|
158
|
+
reference fixture with `uv run python -m tests.span_reference_fixture`.
|
|
159
|
+
|
|
126
160
|
## Two packages, one published distribution
|
|
127
161
|
|
|
128
162
|
`cmpnd` (`cmpnd/`) is the SDK. `cmpnd_ingest` (`ingest/cmpnd_ingest/`) is the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cmpnd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.58.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>
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.15
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
|
-
Requires-Dist: dspy>=3.
|
|
20
|
+
Requires-Dist: dspy>=3.3.0
|
|
21
21
|
Requires-Dist: httpx>=0.27.0
|
|
22
22
|
Requires-Dist: ipython>=8.20
|
|
23
23
|
Requires-Dist: pydantic>=2.0
|
|
@@ -205,6 +205,145 @@ The platform makes the program the first time your organization uses the
|
|
|
205
205
|
program name. Later deploys under the same program name go to the same
|
|
206
206
|
program, and so do the traces of a client that runs it.
|
|
207
207
|
|
|
208
|
+
### Credentials
|
|
209
|
+
|
|
210
|
+
A hosted program spends a credential your organization sealed, and the deploy
|
|
211
|
+
names it. The program's code stays the code you run on your laptop:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
lm = dspy.LM("openai/deepseek-4.1-flash", api_base="https://gw.lunaroute.com/v1") # unchanged
|
|
215
|
+
|
|
216
|
+
luna = cmpnd.credentials.get("luna-exec")
|
|
217
|
+
deployed = sdk.deploy_program(program, credential=luna)
|
|
218
|
+
# deploy: default-lm: chat_completions openai/deepseek-4.1-flash → luna-exec (https://gw.lunaroute.com)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- `cmpnd.credentials.get(name)` returns a `cmpnd.Credential` holding the name,
|
|
222
|
+
the protocols its endpoint serves and its `api_base`. It holds no key. A name
|
|
223
|
+
the organization does not hold raises `cmpnd.CredentialNotFound`, which lists
|
|
224
|
+
the names it does hold and the nearest one. `cmpnd.credentials.list()`
|
|
225
|
+
returns them all.
|
|
226
|
+
- `credential=` takes a `cmpnd.Credential`, never a string. A string raises
|
|
227
|
+
and shows the `cmpnd.credentials.get(...)` line to write.
|
|
228
|
+
- Without `credential=`, the deployment spends the organization's default,
|
|
229
|
+
which an owner sets with `cmpnd credentials default NAME`.
|
|
230
|
+
- The deployment records the credential's name. Each call spends the newest
|
|
231
|
+
credential sealed under that name, so an owner who rotates a key needs no
|
|
232
|
+
redeploy.
|
|
233
|
+
- The deploy prints the protocol, model and credential of each binding, as
|
|
234
|
+
above. A server that prints none chose the credential from the model's
|
|
235
|
+
provider prefix, and the SDK warns.
|
|
236
|
+
- A hosted call goes to the credential's `api_base`. The LM's own `api_base`
|
|
237
|
+
serves your laptop run and is not sent.
|
|
238
|
+
|
|
239
|
+
Keys never leave your laptop. The SDK sends no key on the LM, and a key reaches
|
|
240
|
+
the platform only through `cmpnd credentials create`. `cmpnd deploy FILE`
|
|
241
|
+
refuses source whose import builds an LM carrying a key, and names the module,
|
|
242
|
+
the model and the field.
|
|
243
|
+
|
|
244
|
+
### The same source on your laptop and hosted
|
|
245
|
+
|
|
246
|
+
A program's logic runs unchanged on your laptop and hosted. On your laptop it
|
|
247
|
+
spends the key in your environment. Hosted, it spends a credential your
|
|
248
|
+
organization sealed. Keep the logic in one file and let a small entry point
|
|
249
|
+
choose where it runs.
|
|
250
|
+
|
|
251
|
+
The program file holds the logic and names its model. It holds no key:
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
# qa.py
|
|
255
|
+
import dspy
|
|
256
|
+
|
|
257
|
+
lm = dspy.LM("openai/gpt-5-mini") # no api_key: litellm reads OPENAI_API_KEY on your laptop
|
|
258
|
+
program = dspy.Predict("question -> answer")
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def metric(gold, pred, trace=None, pred_name=None, pred_trace=None, lms=None):
|
|
262
|
+
verdict = dspy.Predict("answer, gold -> correct: bool")(answer=pred.answer, gold=gold.answer, lm=lms["critic"])
|
|
263
|
+
return dspy.Prediction(score=float(verdict.correct), feedback="correct" if verdict.correct else "wrong")
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Seal the key once for the organization and make it the default:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
printf '%s' "$OPENAI_API_KEY" | cmpnd credentials create --name openai --preset openai
|
|
270
|
+
cmpnd credentials default openai
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The entry point is the only code that knows where the run happens:
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
# main.py
|
|
277
|
+
import functools
|
|
278
|
+
import sys
|
|
279
|
+
|
|
280
|
+
import cmpnd
|
|
281
|
+
import dspy
|
|
282
|
+
|
|
283
|
+
from qa import lm, metric, program
|
|
284
|
+
|
|
285
|
+
HOSTED = "--hosted" in sys.argv
|
|
286
|
+
|
|
287
|
+
sdk = cmpnd.Client()
|
|
288
|
+
qa = cmpnd.Program("qa", module=program, lm=lm)
|
|
289
|
+
reflection = dspy.LM("openai/gpt-5", max_tokens=32000)
|
|
290
|
+
lms = {"critic": dspy.LM("openai/gpt-5-mini")}
|
|
291
|
+
train, val = load_examples() # your dspy.Example lists
|
|
292
|
+
|
|
293
|
+
if HOSTED:
|
|
294
|
+
deployed = sdk.deploy_program(qa) # spends the default credential, openai
|
|
295
|
+
print(sdk.run_deployment(deployed, question="What is DSPy?"))
|
|
296
|
+
best = sdk.optimize_deployment(
|
|
297
|
+
deployed,
|
|
298
|
+
trainset=train,
|
|
299
|
+
valset=val,
|
|
300
|
+
metric=metric, # the platform hands it lms
|
|
301
|
+
reflection_lm=cmpnd.HostedLM(reflection),
|
|
302
|
+
lms={name: cmpnd.HostedLM(model) for name, model in lms.items()},
|
|
303
|
+
auto="light",
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
print(sdk.run_program(qa, question="What is DSPy?")) # spends $OPENAI_API_KEY
|
|
307
|
+
gepa = dspy.GEPA(metric=functools.partial(metric, lms=lms), reflection_lm=reflection, auto="light")
|
|
308
|
+
best = sdk.optimize_program(qa, gepa, trainset=train, valset=val)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`python main.py` runs everything on your laptop, and `python main.py --hosted`
|
|
312
|
+
runs it on the platform. `cmpnd deploy qa.py qa` deploys the same file from the
|
|
313
|
+
terminal.
|
|
314
|
+
|
|
315
|
+
| | On your laptop | Hosted |
|
|
316
|
+
|---|---|---|
|
|
317
|
+
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default |
|
|
318
|
+
| Address | the LM's `api_base`, else the provider's endpoint | the credential's `api_base` |
|
|
319
|
+
| Model | `gpt-5-mini`, the model after its first `/` | `gpt-5-mini` |
|
|
320
|
+
| The metric's `lms` | the dict the entry point binds | the run's `lms=`, which the platform hands it |
|
|
321
|
+
|
|
322
|
+
These rules keep the program file portable:
|
|
323
|
+
|
|
324
|
+
- **Leave the key off the program's LM** and let litellm read the provider's
|
|
325
|
+
own variable. For a key in a variable litellm does not read, write
|
|
326
|
+
`api_key=os.environ.get("NAME")`. cmpnd imports a deploy file with an empty
|
|
327
|
+
environment, so the key is `None` there and present on your laptop.
|
|
328
|
+
- **Never write a key into the file, and never read it as
|
|
329
|
+
`os.environ["NAME"]` at module scope.** The deploy refuses the first. The
|
|
330
|
+
second raises `KeyError` hosted, where the environment holds no key.
|
|
331
|
+
- **Seal the credential at the address your laptop LM reaches.** A program
|
|
332
|
+
that sets `api_base="https://gw.lunaroute.com/v1"` needs a credential sealed
|
|
333
|
+
there, with `--preset lunaroute` or `--api-base`. Hosted calls go to the
|
|
334
|
+
credential's address and ignore the LM's `api_base`. The deploy prints the
|
|
335
|
+
address it chose, so you can compare the two.
|
|
336
|
+
- **Wrap a model you hand the hosted optimization in `cmpnd.HostedLM`.** The
|
|
337
|
+
entry point builds `reflection_lm=` and each `lms=` entry, so those LMs may
|
|
338
|
+
hold a key for the laptop run. The wrapper leaves that key on your machine.
|
|
339
|
+
`optimize_deployment` refuses a key on an unwrapped LM, because there it would
|
|
340
|
+
look spent. `cmpnd.HostedLM(model, credential=c)` makes a model spend a
|
|
341
|
+
credential other than the run's.
|
|
342
|
+
|
|
343
|
+
A judge built on `dspy.experimental.TypeSafe` also runs unchanged in both
|
|
344
|
+
places. [`docs/sdk-instrumentation.md`](docs/sdk-instrumentation.md), under
|
|
345
|
+
"System One judges", describes the hosted side.
|
|
346
|
+
|
|
208
347
|
### Options
|
|
209
348
|
|
|
210
349
|
```python
|
|
@@ -213,6 +352,7 @@ sdk.deploy_program(
|
|
|
213
352
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
214
353
|
timeout=300, # optional: seconds to wait for the deployment to be ready
|
|
215
354
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
355
|
+
credential=None, # optional: a cmpnd.Credential the program's model spends
|
|
216
356
|
)
|
|
217
357
|
```
|
|
218
358
|
|
|
@@ -270,11 +410,32 @@ from the deployment.
|
|
|
270
410
|
`reflection_lm` is the model that proposes each new instruction. The search is
|
|
271
411
|
only as good as this model, so it is usually a strong model and not the one
|
|
272
412
|
being optimized. A `dspy.LM` passes its sampling settings to the provider. A
|
|
273
|
-
bare model name gives the same model with no sampling settings.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
413
|
+
bare model name gives the same model with no sampling settings. A run spends
|
|
414
|
+
sealed credentials only, so the SDK refuses a key on the LM before any network
|
|
415
|
+
call. `cmpnd.HostedLM(lm)` keeps a key your laptop runs spend on this machine
|
|
416
|
+
and passes the LM's model and sampling.
|
|
417
|
+
|
|
418
|
+
`credential=` names the run's credential, which every binding that names none
|
|
419
|
+
spends: the program's model, the reflection model and each entry of `lms`. A
|
|
420
|
+
binding names its own credential through a wrapper for its protocol:
|
|
421
|
+
|
|
422
|
+
```python
|
|
423
|
+
luna = cmpnd.credentials.get("luna-exec") # serves chat_completions and system_one
|
|
424
|
+
openai = cmpnd.credentials.get("openai")
|
|
425
|
+
best = sdk.optimize_deployment(
|
|
426
|
+
deployed, trainset=train, valset=val, metric=metric,
|
|
427
|
+
credential=luna,
|
|
428
|
+
reflection_lm=cmpnd.HostedLM(dspy.LM("openai/gpt-5"), credential=openai),
|
|
429
|
+
lms={"judge": cmpnd.SystemOne("lunaroute/djev", credential=luna)},
|
|
430
|
+
auto="light",
|
|
431
|
+
)
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
`cmpnd.HostedLM(lm, credential=c)` wraps a chat LM, and
|
|
435
|
+
`cmpnd.SystemOne(model, credential=c)` declares a System One model. A binding
|
|
436
|
+
without a credential spends the run's, or the organization's default. The
|
|
437
|
+
platform refuses a credential whose endpoint does not serve a binding's
|
|
438
|
+
protocol, and names the `credential=` to add.
|
|
278
439
|
|
|
279
440
|
The SDK checks the metric before any network call. GEPA writes each new
|
|
280
441
|
instruction from the textual feedback the metric returns, so it needs a
|
|
@@ -322,9 +483,9 @@ rules:
|
|
|
322
483
|
names.
|
|
323
484
|
- `"default-lm"` is reserved for the program's own model, which comes from the
|
|
324
485
|
deployment. Declaring it raises an error that names it.
|
|
325
|
-
- The platform refuses a
|
|
326
|
-
the run, before the run starts. These LMs, like `reflection_lm`, must not
|
|
327
|
-
|
|
486
|
+
- The platform refuses a binding it finds no credential for when it dispatches
|
|
487
|
+
the run, before the run starts. These LMs, like `reflection_lm`, must not
|
|
488
|
+
carry a key.
|
|
328
489
|
|
|
329
490
|
The `lms` parameter does not change the arity check. Five or more positional
|
|
330
491
|
arguments make a feedback metric, and a metric without `lms` never receives
|
|
@@ -340,8 +501,9 @@ sdk.optimize_deployment(
|
|
|
340
501
|
valset=val, # required: validation examples
|
|
341
502
|
metric=metric, # required: the metric, arity-checked
|
|
342
503
|
config=None, # optional: optimizer config, allow-listed by the platform
|
|
343
|
-
reflection_lm=None, # required: a dspy.LM
|
|
344
|
-
lms=None, # optional: name -> dspy.LM,
|
|
504
|
+
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
505
|
+
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
506
|
+
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
345
507
|
max_metric_calls=None, # budget: the metric-call ceiling for one step
|
|
346
508
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
347
509
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
@@ -154,6 +154,145 @@ The platform makes the program the first time your organization uses the
|
|
|
154
154
|
program name. Later deploys under the same program name go to the same
|
|
155
155
|
program, and so do the traces of a client that runs it.
|
|
156
156
|
|
|
157
|
+
### Credentials
|
|
158
|
+
|
|
159
|
+
A hosted program spends a credential your organization sealed, and the deploy
|
|
160
|
+
names it. The program's code stays the code you run on your laptop:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
lm = dspy.LM("openai/deepseek-4.1-flash", api_base="https://gw.lunaroute.com/v1") # unchanged
|
|
164
|
+
|
|
165
|
+
luna = cmpnd.credentials.get("luna-exec")
|
|
166
|
+
deployed = sdk.deploy_program(program, credential=luna)
|
|
167
|
+
# deploy: default-lm: chat_completions openai/deepseek-4.1-flash → luna-exec (https://gw.lunaroute.com)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- `cmpnd.credentials.get(name)` returns a `cmpnd.Credential` holding the name,
|
|
171
|
+
the protocols its endpoint serves and its `api_base`. It holds no key. A name
|
|
172
|
+
the organization does not hold raises `cmpnd.CredentialNotFound`, which lists
|
|
173
|
+
the names it does hold and the nearest one. `cmpnd.credentials.list()`
|
|
174
|
+
returns them all.
|
|
175
|
+
- `credential=` takes a `cmpnd.Credential`, never a string. A string raises
|
|
176
|
+
and shows the `cmpnd.credentials.get(...)` line to write.
|
|
177
|
+
- Without `credential=`, the deployment spends the organization's default,
|
|
178
|
+
which an owner sets with `cmpnd credentials default NAME`.
|
|
179
|
+
- The deployment records the credential's name. Each call spends the newest
|
|
180
|
+
credential sealed under that name, so an owner who rotates a key needs no
|
|
181
|
+
redeploy.
|
|
182
|
+
- The deploy prints the protocol, model and credential of each binding, as
|
|
183
|
+
above. A server that prints none chose the credential from the model's
|
|
184
|
+
provider prefix, and the SDK warns.
|
|
185
|
+
- A hosted call goes to the credential's `api_base`. The LM's own `api_base`
|
|
186
|
+
serves your laptop run and is not sent.
|
|
187
|
+
|
|
188
|
+
Keys never leave your laptop. The SDK sends no key on the LM, and a key reaches
|
|
189
|
+
the platform only through `cmpnd credentials create`. `cmpnd deploy FILE`
|
|
190
|
+
refuses source whose import builds an LM carrying a key, and names the module,
|
|
191
|
+
the model and the field.
|
|
192
|
+
|
|
193
|
+
### The same source on your laptop and hosted
|
|
194
|
+
|
|
195
|
+
A program's logic runs unchanged on your laptop and hosted. On your laptop it
|
|
196
|
+
spends the key in your environment. Hosted, it spends a credential your
|
|
197
|
+
organization sealed. Keep the logic in one file and let a small entry point
|
|
198
|
+
choose where it runs.
|
|
199
|
+
|
|
200
|
+
The program file holds the logic and names its model. It holds no key:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
# qa.py
|
|
204
|
+
import dspy
|
|
205
|
+
|
|
206
|
+
lm = dspy.LM("openai/gpt-5-mini") # no api_key: litellm reads OPENAI_API_KEY on your laptop
|
|
207
|
+
program = dspy.Predict("question -> answer")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def metric(gold, pred, trace=None, pred_name=None, pred_trace=None, lms=None):
|
|
211
|
+
verdict = dspy.Predict("answer, gold -> correct: bool")(answer=pred.answer, gold=gold.answer, lm=lms["critic"])
|
|
212
|
+
return dspy.Prediction(score=float(verdict.correct), feedback="correct" if verdict.correct else "wrong")
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Seal the key once for the organization and make it the default:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
printf '%s' "$OPENAI_API_KEY" | cmpnd credentials create --name openai --preset openai
|
|
219
|
+
cmpnd credentials default openai
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The entry point is the only code that knows where the run happens:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
# main.py
|
|
226
|
+
import functools
|
|
227
|
+
import sys
|
|
228
|
+
|
|
229
|
+
import cmpnd
|
|
230
|
+
import dspy
|
|
231
|
+
|
|
232
|
+
from qa import lm, metric, program
|
|
233
|
+
|
|
234
|
+
HOSTED = "--hosted" in sys.argv
|
|
235
|
+
|
|
236
|
+
sdk = cmpnd.Client()
|
|
237
|
+
qa = cmpnd.Program("qa", module=program, lm=lm)
|
|
238
|
+
reflection = dspy.LM("openai/gpt-5", max_tokens=32000)
|
|
239
|
+
lms = {"critic": dspy.LM("openai/gpt-5-mini")}
|
|
240
|
+
train, val = load_examples() # your dspy.Example lists
|
|
241
|
+
|
|
242
|
+
if HOSTED:
|
|
243
|
+
deployed = sdk.deploy_program(qa) # spends the default credential, openai
|
|
244
|
+
print(sdk.run_deployment(deployed, question="What is DSPy?"))
|
|
245
|
+
best = sdk.optimize_deployment(
|
|
246
|
+
deployed,
|
|
247
|
+
trainset=train,
|
|
248
|
+
valset=val,
|
|
249
|
+
metric=metric, # the platform hands it lms
|
|
250
|
+
reflection_lm=cmpnd.HostedLM(reflection),
|
|
251
|
+
lms={name: cmpnd.HostedLM(model) for name, model in lms.items()},
|
|
252
|
+
auto="light",
|
|
253
|
+
)
|
|
254
|
+
else:
|
|
255
|
+
print(sdk.run_program(qa, question="What is DSPy?")) # spends $OPENAI_API_KEY
|
|
256
|
+
gepa = dspy.GEPA(metric=functools.partial(metric, lms=lms), reflection_lm=reflection, auto="light")
|
|
257
|
+
best = sdk.optimize_program(qa, gepa, trainset=train, valset=val)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`python main.py` runs everything on your laptop, and `python main.py --hosted`
|
|
261
|
+
runs it on the platform. `cmpnd deploy qa.py qa` deploys the same file from the
|
|
262
|
+
terminal.
|
|
263
|
+
|
|
264
|
+
| | On your laptop | Hosted |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| Key | the provider's variable in your environment, such as `OPENAI_API_KEY` | the credential the call names, else the organization's default |
|
|
267
|
+
| Address | the LM's `api_base`, else the provider's endpoint | the credential's `api_base` |
|
|
268
|
+
| Model | `gpt-5-mini`, the model after its first `/` | `gpt-5-mini` |
|
|
269
|
+
| The metric's `lms` | the dict the entry point binds | the run's `lms=`, which the platform hands it |
|
|
270
|
+
|
|
271
|
+
These rules keep the program file portable:
|
|
272
|
+
|
|
273
|
+
- **Leave the key off the program's LM** and let litellm read the provider's
|
|
274
|
+
own variable. For a key in a variable litellm does not read, write
|
|
275
|
+
`api_key=os.environ.get("NAME")`. cmpnd imports a deploy file with an empty
|
|
276
|
+
environment, so the key is `None` there and present on your laptop.
|
|
277
|
+
- **Never write a key into the file, and never read it as
|
|
278
|
+
`os.environ["NAME"]` at module scope.** The deploy refuses the first. The
|
|
279
|
+
second raises `KeyError` hosted, where the environment holds no key.
|
|
280
|
+
- **Seal the credential at the address your laptop LM reaches.** A program
|
|
281
|
+
that sets `api_base="https://gw.lunaroute.com/v1"` needs a credential sealed
|
|
282
|
+
there, with `--preset lunaroute` or `--api-base`. Hosted calls go to the
|
|
283
|
+
credential's address and ignore the LM's `api_base`. The deploy prints the
|
|
284
|
+
address it chose, so you can compare the two.
|
|
285
|
+
- **Wrap a model you hand the hosted optimization in `cmpnd.HostedLM`.** The
|
|
286
|
+
entry point builds `reflection_lm=` and each `lms=` entry, so those LMs may
|
|
287
|
+
hold a key for the laptop run. The wrapper leaves that key on your machine.
|
|
288
|
+
`optimize_deployment` refuses a key on an unwrapped LM, because there it would
|
|
289
|
+
look spent. `cmpnd.HostedLM(model, credential=c)` makes a model spend a
|
|
290
|
+
credential other than the run's.
|
|
291
|
+
|
|
292
|
+
A judge built on `dspy.experimental.TypeSafe` also runs unchanged in both
|
|
293
|
+
places. [`docs/sdk-instrumentation.md`](docs/sdk-instrumentation.md), under
|
|
294
|
+
"System One judges", describes the hosted side.
|
|
295
|
+
|
|
157
296
|
### Options
|
|
158
297
|
|
|
159
298
|
```python
|
|
@@ -162,6 +301,7 @@ sdk.deploy_program(
|
|
|
162
301
|
metric=None, # optional: a metric callable, packaged for optimization
|
|
163
302
|
timeout=300, # optional: seconds to wait for the deployment to be ready
|
|
164
303
|
metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
|
|
304
|
+
credential=None, # optional: a cmpnd.Credential the program's model spends
|
|
165
305
|
)
|
|
166
306
|
```
|
|
167
307
|
|
|
@@ -219,11 +359,32 @@ from the deployment.
|
|
|
219
359
|
`reflection_lm` is the model that proposes each new instruction. The search is
|
|
220
360
|
only as good as this model, so it is usually a strong model and not the one
|
|
221
361
|
being optimized. A `dspy.LM` passes its sampling settings to the provider. A
|
|
222
|
-
bare model name gives the same model with no sampling settings.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
362
|
+
bare model name gives the same model with no sampling settings. A run spends
|
|
363
|
+
sealed credentials only, so the SDK refuses a key on the LM before any network
|
|
364
|
+
call. `cmpnd.HostedLM(lm)` keeps a key your laptop runs spend on this machine
|
|
365
|
+
and passes the LM's model and sampling.
|
|
366
|
+
|
|
367
|
+
`credential=` names the run's credential, which every binding that names none
|
|
368
|
+
spends: the program's model, the reflection model and each entry of `lms`. A
|
|
369
|
+
binding names its own credential through a wrapper for its protocol:
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
luna = cmpnd.credentials.get("luna-exec") # serves chat_completions and system_one
|
|
373
|
+
openai = cmpnd.credentials.get("openai")
|
|
374
|
+
best = sdk.optimize_deployment(
|
|
375
|
+
deployed, trainset=train, valset=val, metric=metric,
|
|
376
|
+
credential=luna,
|
|
377
|
+
reflection_lm=cmpnd.HostedLM(dspy.LM("openai/gpt-5"), credential=openai),
|
|
378
|
+
lms={"judge": cmpnd.SystemOne("lunaroute/djev", credential=luna)},
|
|
379
|
+
auto="light",
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
`cmpnd.HostedLM(lm, credential=c)` wraps a chat LM, and
|
|
384
|
+
`cmpnd.SystemOne(model, credential=c)` declares a System One model. A binding
|
|
385
|
+
without a credential spends the run's, or the organization's default. The
|
|
386
|
+
platform refuses a credential whose endpoint does not serve a binding's
|
|
387
|
+
protocol, and names the `credential=` to add.
|
|
227
388
|
|
|
228
389
|
The SDK checks the metric before any network call. GEPA writes each new
|
|
229
390
|
instruction from the textual feedback the metric returns, so it needs a
|
|
@@ -271,9 +432,9 @@ rules:
|
|
|
271
432
|
names.
|
|
272
433
|
- `"default-lm"` is reserved for the program's own model, which comes from the
|
|
273
434
|
deployment. Declaring it raises an error that names it.
|
|
274
|
-
- The platform refuses a
|
|
275
|
-
the run, before the run starts. These LMs, like `reflection_lm`, must not
|
|
276
|
-
|
|
435
|
+
- The platform refuses a binding it finds no credential for when it dispatches
|
|
436
|
+
the run, before the run starts. These LMs, like `reflection_lm`, must not
|
|
437
|
+
carry a key.
|
|
277
438
|
|
|
278
439
|
The `lms` parameter does not change the arity check. Five or more positional
|
|
279
440
|
arguments make a feedback metric, and a metric without `lms` never receives
|
|
@@ -289,8 +450,9 @@ sdk.optimize_deployment(
|
|
|
289
450
|
valset=val, # required: validation examples
|
|
290
451
|
metric=metric, # required: the metric, arity-checked
|
|
291
452
|
config=None, # optional: optimizer config, allow-listed by the platform
|
|
292
|
-
reflection_lm=None, # required: a dspy.LM
|
|
293
|
-
lms=None, # optional: name -> dspy.LM,
|
|
453
|
+
reflection_lm=None, # required: a dspy.LM, a bare model name or a cmpnd.HostedLM
|
|
454
|
+
lms=None, # optional: name -> dspy.LM, cmpnd.HostedLM or cmpnd.SystemOne
|
|
455
|
+
credential=None, # optional: the cmpnd.Credential every other binding spends
|
|
294
456
|
max_metric_calls=None, # budget: the metric-call ceiling for one step
|
|
295
457
|
auto=None, # budget: "light", "medium" or "heavy"
|
|
296
458
|
may_author_code=None, # optional: False keeps each dspy.Flex at its deployed source
|
|
@@ -17,7 +17,7 @@ from typing import TYPE_CHECKING
|
|
|
17
17
|
|
|
18
18
|
from cmpnd_ingest.client_floor import UpgradeRequiredWarning
|
|
19
19
|
|
|
20
|
-
from . import authored, programs, traces
|
|
20
|
+
from . import authored, credentials, programs, traces
|
|
21
21
|
from ._http import ApiError
|
|
22
22
|
from .callback import CmpndCallback, trace_id
|
|
23
23
|
from .client import Client
|
|
@@ -27,6 +27,7 @@ from .context import (
|
|
|
27
27
|
get_current_span,
|
|
28
28
|
get_current_trace,
|
|
29
29
|
)
|
|
30
|
+
from .credentials import Credential, CredentialNotFound
|
|
30
31
|
from .datasets import DatasetNotFoundError, VersionNotFoundError, load_dataset
|
|
31
32
|
from .decorators import start_span, trace
|
|
32
33
|
from .deployment import DeployFailed
|
|
@@ -39,7 +40,7 @@ from .deployment_metadata import (
|
|
|
39
40
|
from .deployment_runs import RunResultExpired, RunSubmissionUncertain, RunWaitTimeout
|
|
40
41
|
from .execution import DeployedProgram, RetryableProviderError
|
|
41
42
|
from .exporter import flush_exporter, shutdown_exporter
|
|
42
|
-
from .lm_configuration import SystemOne, configure_lm
|
|
43
|
+
from .lm_configuration import HostedLM, SystemOne, configure_lm
|
|
43
44
|
from .mcp_servers import (
|
|
44
45
|
Bearer,
|
|
45
46
|
McpToolReference,
|
|
@@ -70,6 +71,7 @@ __all__ = [
|
|
|
70
71
|
"configure",
|
|
71
72
|
"configure_lm",
|
|
72
73
|
"SystemOne",
|
|
74
|
+
"HostedLM",
|
|
73
75
|
"get_config",
|
|
74
76
|
"require_config",
|
|
75
77
|
# Main callback
|
|
@@ -95,6 +97,10 @@ __all__ = [
|
|
|
95
97
|
"traces",
|
|
96
98
|
# Program name checks (cmpnd.programs.validate_program_name)
|
|
97
99
|
"programs",
|
|
100
|
+
# The organization's provider credentials (cmpnd.credentials.get / list)
|
|
101
|
+
"credentials",
|
|
102
|
+
"Credential",
|
|
103
|
+
"CredentialNotFound",
|
|
98
104
|
# A program declared by name
|
|
99
105
|
"Program",
|
|
100
106
|
"program",
|