cmpnd 0.57.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.
Files changed (390) hide show
  1. {cmpnd-0.57.0 → cmpnd-0.58.0}/AGENTS.md +34 -0
  2. {cmpnd-0.57.0 → cmpnd-0.58.0}/PKG-INFO +2 -2
  3. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_authored_import.py +1 -1
  4. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_gepa_patch.py +6 -9
  5. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/callback.py +1 -1
  6. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimizers/tracker.py +3 -5
  7. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/cli.md +0 -3
  8. {cmpnd-0.57.0 → cmpnd-0.58.0}/pyproject.toml +31 -4
  9. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/check-pip-install.sh +1 -1
  10. cmpnd-0.58.0/scripts/install-test-env.sh +67 -0
  11. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/test-in-linux.sh +8 -7
  12. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/span_reference_fixture.py +13 -7
  13. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_adapter_reentrancy.py +2 -8
  14. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_lm_usage_shapes.py +2 -4
  15. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_program_lineage_persist.py +4 -5
  16. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_rlm_patch.py +19 -6
  17. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_span_references.py +3 -3
  18. {cmpnd-0.57.0 → cmpnd-0.58.0}/uv.lock +421 -194
  19. {cmpnd-0.57.0 → cmpnd-0.58.0}/.gitignore +0 -0
  20. {cmpnd-0.57.0 → cmpnd-0.58.0}/CLAUDE.md +0 -0
  21. {cmpnd-0.57.0 → cmpnd-0.58.0}/README.md +0 -0
  22. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/__init__.py +0 -0
  23. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_assessments.py +0 -0
  24. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_deployments.py +0 -0
  25. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_exporter_pool.py +0 -0
  26. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_http.py +0 -0
  27. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_program_patch.py +0 -0
  28. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_rlm_patch.py +0 -0
  29. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_runtime_tools.py +0 -0
  30. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_timespec.py +0 -0
  31. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_traces.py +0 -0
  32. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/_valsets.py +0 -0
  33. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/authored.py +0 -0
  34. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/__init__.py +0 -0
  35. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/api_client.py +0 -0
  36. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/__init__.py +0 -0
  37. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/admin.py +0 -0
  38. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/assessments.py +0 -0
  39. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/auth.py +0 -0
  40. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/datasets.py +0 -0
  41. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/deployments.py +0 -0
  42. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/evals.py +0 -0
  43. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/login.py +0 -0
  44. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/optimizations.py +0 -0
  45. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/org.py +0 -0
  46. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/programs.py +0 -0
  47. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  48. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/signatures.py +0 -0
  49. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  50. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/top.py +0 -0
  51. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/traces.py +0 -0
  52. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/commands/valsets.py +0 -0
  53. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/credentials.py +0 -0
  54. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/deprecation.py +0 -0
  55. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/pagination.py +0 -0
  56. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/shell.py +0 -0
  57. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/trace_render.py +0 -0
  58. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/tree_help.py +0 -0
  59. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/cli/verbs.py +0 -0
  60. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/client.py +0 -0
  61. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/configuration.py +0 -0
  62. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/context.py +0 -0
  63. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/credentials.py +0 -0
  64. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/dataset_sync.py +0 -0
  65. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/datasets.py +0 -0
  66. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/decorators.py +0 -0
  67. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/deployment.py +0 -0
  68. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/deployment_metadata.py +0 -0
  69. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/deployment_runs.py +0 -0
  70. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/eval_handler.py +0 -0
  71. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/execution.py +0 -0
  72. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/exporter.py +0 -0
  73. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/exporter_http.py +0 -0
  74. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/helpers.py +0 -0
  75. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/identity.py +0 -0
  76. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/imaging.py +0 -0
  77. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/__init__.py +0 -0
  78. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/decode.py +0 -0
  79. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/encode.py +0 -0
  80. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/hash.py +0 -0
  81. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/program.py +0 -0
  82. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/reflection.py +0 -0
  83. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/types.py +0 -0
  84. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/ir/xxh64.py +0 -0
  85. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/lm_configuration.py +0 -0
  86. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/mcp_servers.py +0 -0
  87. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/models.py +0 -0
  88. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/named_programs.py +0 -0
  89. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimization.py +0 -0
  90. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimizers/__init__.py +0 -0
  91. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimizers/gepa.py +0 -0
  92. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  93. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/optimizers/resume.py +0 -0
  94. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/packaging.py +0 -0
  95. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/programs.py +0 -0
  96. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/references.py +0 -0
  97. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/retry.py +0 -0
  98. {cmpnd-0.57.0 → cmpnd-0.58.0}/cmpnd/traces.py +0 -0
  99. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/2026-04-02-code-review.md +0 -0
  100. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/client.md +0 -0
  101. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/custom-proposer.md +0 -0
  102. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  103. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  104. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/reading-traces.md +0 -0
  105. {cmpnd-0.57.0 → cmpnd-0.58.0}/docs/sdk-instrumentation.md +0 -0
  106. {cmpnd-0.57.0 → cmpnd-0.58.0}/examples/generalizing_proposer.py +0 -0
  107. {cmpnd-0.57.0 → cmpnd-0.58.0}/examples/local_ollama.py +0 -0
  108. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/LINEAGE.md +0 -0
  109. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/README.md +0 -0
  110. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  111. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  112. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  113. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  114. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  115. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  116. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/py.typed +0 -0
  117. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  118. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/retry.py +0 -0
  119. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  120. {cmpnd-0.57.0 → cmpnd-0.58.0}/ingest/pyproject.toml +0 -0
  121. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/audit-sdist.sh +0 -0
  122. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/capture_review_run.py +0 -0
  123. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/check_release_artifacts.py +0 -0
  124. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/fixtures/review_run.json.gz +0 -0
  125. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/gepa_resume_bug.py +0 -0
  126. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/release-stress.sh +0 -0
  127. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/require_version_bump.py +0 -0
  128. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/seed_review_run.py +0 -0
  129. {cmpnd-0.57.0 → cmpnd-0.58.0}/scripts/selfhost_compat.py +0 -0
  130. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/__init__.pyi +0 -0
  131. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  132. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  133. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/utils/__init__.pyi +0 -0
  134. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/utils/callback.pyi +0 -0
  135. {cmpnd-0.57.0 → cmpnd-0.58.0}/stubs/dspy/utils/dummies.pyi +0 -0
  136. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/__init__.py +0 -0
  137. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_credential_route.py +0 -0
  138. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_deployment_signature_helpers.py +0 -0
  139. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_exporter_helpers.py +0 -0
  140. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_fake_clock.py +0 -0
  141. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_identity_helpers.py +0 -0
  142. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_resolve_refs.py +0 -0
  143. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/_traced_run.py +0 -0
  144. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/conftest.py +0 -0
  145. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/__init__.py +0 -0
  146. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/committee_task.py +0 -0
  147. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/conftest.py +0 -0
  148. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  149. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  150. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/fake_lm.py +0 -0
  151. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/helpers.py +0 -0
  152. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/target_capabilities.py +0 -0
  153. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_assessments_cli.py +0 -0
  154. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_capture_prompts.py +0 -0
  155. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_composite_module.py +0 -0
  156. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  157. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_execute.py +0 -0
  158. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_pandas.py +0 -0
  159. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_deploy_programs.py +0 -0
  160. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_edge_cases.py +0 -0
  161. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_example_hash.py +0 -0
  162. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_gepa_optimization.py +0 -0
  163. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_interpreter_spans.py +0 -0
  164. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_lm_accuracy.py +0 -0
  165. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_module_tracing.py +0 -0
  166. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimization_lineage.py +0 -0
  167. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  168. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_failures.py +0 -0
  169. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_loop.py +0 -0
  170. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  171. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  172. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_parallel_export.py +0 -0
  173. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_project_attribution.py +0 -0
  174. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_react_tool_spans.py +0 -0
  175. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_save_load.py +0 -0
  176. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_trace_structure.py +0 -0
  177. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_traces_read.py +0 -0
  178. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_user_attribution.py +0 -0
  179. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/e2e/test_valsets_cli.py +0 -0
  180. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  181. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  182. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  183. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  184. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  185. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  186. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  187. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  188. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  189. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/10_react.json +0 -0
  190. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/11_refine.json +0 -0
  191. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/12_retrieve.json +0 -0
  192. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/13_knn.json +0 -0
  193. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/14_parallel.json +0 -0
  194. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/identity_vectors/README.md +0 -0
  195. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/ingest_conformance.py +0 -0
  196. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/__init__.py +0 -0
  197. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/authored_optimize/judge.py +0 -0
  198. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  199. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/conftest.py +0 -0
  200. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  201. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/hosted_optimize_probe.py +0 -0
  202. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/optimization_run_probe.py +0 -0
  203. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  204. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/test_logs_renders_traces.py +0 -0
  205. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/test_optimization_run.py +0 -0
  206. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/test_optimizing_progress.py +0 -0
  207. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/integration/test_unhappy_path.py +0 -0
  208. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/__init__.py +0 -0
  209. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/__main__.py +0 -0
  210. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/drain.py +0 -0
  211. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/ingest.py +0 -0
  212. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/latency_transport.py +0 -0
  213. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/rlm_shape.py +0 -0
  214. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/rlm_size_report.py +0 -0
  215. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/sweep.py +0 -0
  216. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/test_rlm_shape.py +0 -0
  217. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/load/test_rlm_size_report.py +0 -0
  218. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/__init__.py +0 -0
  219. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/conftest.py +0 -0
  220. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/seed_parity.py +0 -0
  221. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_auth.py +0 -0
  222. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_datasets.py +0 -0
  223. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_deployments.py +0 -0
  224. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_evals.py +0 -0
  225. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_health.py +0 -0
  226. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_modules.py +0 -0
  227. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_optimizations.py +0 -0
  228. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_programs.py +0 -0
  229. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_signatures.py +0 -0
  230. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_trace_streaming.py +0 -0
  231. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/parity/test_traces.py +0 -0
  232. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/__init__.py +0 -0
  233. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/_provider.py +0 -0
  234. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/_readiness.py +0 -0
  235. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/_reliability.py +0 -0
  236. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/_result.py +0 -0
  237. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/mint_bedrock_token.py +0 -0
  238. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_deploy_programs.py +0 -0
  239. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_multi_client_stress.py +0 -0
  240. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_optimize_client_committee.py +0 -0
  241. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_optimize_loop.py +0 -0
  242. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_optimize_loop_wasm.py +0 -0
  243. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_optimize_stress.py +0 -0
  244. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_provider_roles.py +0 -0
  245. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_readiness.py +0 -0
  246. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_real_provider_twins.py +0 -0
  247. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_reliability.py +0 -0
  248. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_reliability_classify.py +0 -0
  249. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_rlm_wasm.py +0 -0
  250. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/stress/test_trace_search.py +0 -0
  251. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_assessments_api.py +0 -0
  252. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_authored.py +0 -0
  253. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_authored_bundle_collisions.py +0 -0
  254. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_authored_metric_contract.py +0 -0
  255. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_authored_named_models.py +0 -0
  256. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_authored_optimize.py +0 -0
  257. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_callback.py +0 -0
  258. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_candidate_lineage.py +0 -0
  259. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/__init__.py +0 -0
  260. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/conftest.py +0 -0
  261. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_admin.py +0 -0
  262. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_api_client.py +0 -0
  263. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_assessments.py +0 -0
  264. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_auth.py +0 -0
  265. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_credentials.py +0 -0
  266. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_datasets.py +0 -0
  267. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_deployment_runs.py +0 -0
  268. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_deployments.py +0 -0
  269. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_evals.py +0 -0
  270. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_login.py +0 -0
  271. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_main.py +0 -0
  272. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_optimizations.py +0 -0
  273. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_org.py +0 -0
  274. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_pagination.py +0 -0
  275. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_parity.py +0 -0
  276. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_programs.py +0 -0
  277. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_provider_credentials.py +0 -0
  278. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_schema_sample.py +0 -0
  279. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_shell.py +0 -0
  280. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_signatures.py +0 -0
  281. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_tool_servers.py +0 -0
  282. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_top.py +0 -0
  283. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_traces.py +0 -0
  284. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  285. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_tree_help.py +0 -0
  286. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cli/test_valsets.py +0 -0
  287. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_client.py +0 -0
  288. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_client_floor.py +0 -0
  289. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_client_program_names.py +0 -0
  290. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_clustering/__init__.py +0 -0
  291. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_clustering/conftest.py +0 -0
  292. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_clustering/test_edge_cases.py +0 -0
  293. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  294. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_clustering/test_type_conversion.py +0 -0
  295. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_cmp551_grouping_identity.py +0 -0
  296. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_configuration.py +0 -0
  297. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_context.py +0 -0
  298. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_context_propagation.py +0 -0
  299. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_credential_kwargs.py +0 -0
  300. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_credential_selection.py +0 -0
  301. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_credential_values.py +0 -0
  302. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_dataset_polling.py +0 -0
  303. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_dataset_sync.py +0 -0
  304. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_datasets.py +0 -0
  305. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_decision_client_spans.py +0 -0
  306. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_decorators.py +0 -0
  307. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deploy.py +0 -0
  308. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deploy_mcp_tool_references.py +0 -0
  309. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deploy_program_id.py +0 -0
  310. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deployment_metadata.py +0 -0
  311. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deployment_runs.py +0 -0
  312. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_deployments_read.py +0 -0
  313. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_eval.py +0 -0
  314. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_eval_example_attribution.py +0 -0
  315. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_eval_start.py +0 -0
  316. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_eval_trace_grouping.py +0 -0
  317. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_exception_paths.py +0 -0
  318. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_execute.py +0 -0
  319. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_execute_run_identity.py +0 -0
  320. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_exporter.py +0 -0
  321. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_exporter_program_names.py +0 -0
  322. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_exporter_queue.py +0 -0
  323. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_exporter_real.py +0 -0
  324. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_fake_lm.py +0 -0
  325. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_gepa_callback.py +0 -0
  326. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_gepa_integration.py +0 -0
  327. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_gepa_output_normalization.py +0 -0
  328. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_gepa_resume.py +0 -0
  329. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_identity.py +0 -0
  330. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_imaging.py +0 -0
  331. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_import_weight.py +0 -0
  332. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_ingest_conformance.py +0 -0
  333. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_ingest_second_producer.py +0 -0
  334. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_integration.py +0 -0
  335. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_interpreter_callback.py +0 -0
  336. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_ir_encoder_properties.py +0 -0
  337. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_ir_golden_vectors.py +0 -0
  338. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_ir_roundtrip.py +0 -0
  339. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_lm15_native_calls.py +0 -0
  340. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_lm_configuration.py +0 -0
  341. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_mcp_tools.py +0 -0
  342. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_models.py +0 -0
  343. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_multi_client_stress_readiness.py +0 -0
  344. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimization_progress.py +0 -0
  345. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimization_start.py +0 -0
  346. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize.py +0 -0
  347. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_budget.py +0 -0
  348. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_lift.py +0 -0
  349. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_lms.py +0 -0
  350. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_proposer.py +0 -0
  351. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_reflection_lm.py +0 -0
  352. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_optimize_terminal_failure.py +0 -0
  353. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_packaging.py +0 -0
  354. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_packaging_callable_source.py +0 -0
  355. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_packaging_mcp_tools.py +0 -0
  356. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_packaging_program_source.py +0 -0
  357. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_poll_until.py +0 -0
  358. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_program_id_deprecation.py +0 -0
  359. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_program_identity.py +0 -0
  360. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_program_names_in_deploy.py +0 -0
  361. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_programs_create.py +0 -0
  362. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_project_payload.py +0 -0
  363. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_real_provider_twins_readiness.py +0 -0
  364. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_reflector_properties.py +0 -0
  365. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_reflector_smoke.py +0 -0
  366. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_release_stress_script.py +0 -0
  367. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_replaced_names.py +0 -0
  368. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_repro_reactv2_bugs.py +0 -0
  369. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_require_version_bump.py +0 -0
  370. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_retry.py +0 -0
  371. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_reversible_failures.py +0 -0
  372. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_run_attribution_paths.py +0 -0
  373. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_runtime_tools.py +0 -0
  374. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_schemas.py +0 -0
  375. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_seal_lm_credential.py +0 -0
  376. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_seed_review_run.py +0 -0
  377. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_signature_inputs.py +0 -0
  378. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_span_sent_once.py +0 -0
  379. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_system_one.py +0 -0
  380. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_trace_context_concurrency.py +0 -0
  381. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_trace_fact_wire_contract.py +0 -0
  382. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_trace_facts.py +0 -0
  383. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_trace_render.py +0 -0
  384. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_traces_read.py +0 -0
  385. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_tracked_gepa.py +0 -0
  386. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_tracker_enrich.py +0 -0
  387. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_truncation.py +0 -0
  388. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_upload_auth_headers.py +0 -0
  389. {cmpnd-0.57.0 → cmpnd-0.58.0}/tests/test_valsets_api.py +0 -0
  390. {cmpnd-0.57.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.57.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.1.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
@@ -25,7 +25,7 @@ def _built_lms(root: Path):
25
25
 
26
26
  The check reads objects the import built and parses no source. It wraps the
27
27
  ``__init__`` of ``dspy.BaseLM`` and of every LM class that defines its own, because
28
- ``dspy.LM`` before dspy 3.3 never calls ``BaseLM.__init__``. It names the innermost
28
+ an LM subclass need not call ``BaseLM.__init__``. It names the innermost
29
29
  module of the bundle on the stack, so an LM a helper module builds is named by that
30
30
  module, and records each LM once, however many of the wrapped constructors it runs.
31
31
  """
@@ -172,9 +172,6 @@ def patch_gepa() -> None:
172
172
 
173
173
  import dspy
174
174
 
175
- if not hasattr(dspy, "GEPA"):
176
- return
177
-
178
175
  # Resolve callback support once, at patch time — not per compile — so the
179
176
  # answer matches the installed gepa the patch bound to.
180
177
  has_callbacks = _gepa_supports_callbacks()
@@ -223,10 +220,10 @@ def unpatch_gepa() -> None:
223
220
  _gepa_patched = False
224
221
  return
225
222
 
226
- GEPA = getattr(dspy, "GEPA", None)
227
- if GEPA is not None and hasattr(GEPA, "_cmpnd_original_init"):
228
- GEPA.__init__ = GEPA._cmpnd_original_init
229
- GEPA.compile = GEPA._cmpnd_original_compile
230
- del GEPA._cmpnd_original_init
231
- del GEPA._cmpnd_original_compile
223
+ GEPA = dspy.GEPA
224
+ if hasattr(GEPA, "_cmpnd_original_init"):
225
+ GEPA.__init__ = GEPA._cmpnd_original_init # pyright: ignore[reportAttributeAccessIssue]
226
+ GEPA.compile = GEPA._cmpnd_original_compile # pyright: ignore[reportAttributeAccessIssue]
227
+ del GEPA._cmpnd_original_init # pyright: ignore[reportAttributeAccessIssue]
228
+ del GEPA._cmpnd_original_compile # pyright: ignore[reportAttributeAccessIssue]
232
229
  _gepa_patched = False
@@ -1101,7 +1101,7 @@ class _ModuleMixin(_CallbackBase):
1101
1101
  """Map DSPy module instance to span type."""
1102
1102
  if isinstance(instance, dspy.Retrieve):
1103
1103
  return models.SpanType.RETRIEVE
1104
- elif isinstance(instance, getattr(dspy, "RLM", type(None))):
1104
+ elif isinstance(instance, dspy.RLM):
1105
1105
  return models.SpanType.RLM
1106
1106
  elif isinstance(instance, dspy.ReAct):
1107
1107
  return models.SpanType.REACT
@@ -1332,15 +1332,13 @@ def code_component_types(student: Any) -> dict[str, str]:
1332
1332
  serve cannot tell source from prose on its own, and without this a Flex's module
1333
1333
  source renders as a word-diffed paragraph.
1334
1334
 
1335
- Empty for a program with no Flex, for a dspy without `Flex`, and for anything that is
1336
- not a dspy module.
1335
+ Empty for a program with no Flex, and for anything that is not a dspy module.
1337
1336
  """
1338
1337
  import dspy
1339
1338
 
1340
- flex_cls = getattr(dspy, "Flex", None)
1341
- if flex_cls is None or not isinstance(student, dspy.Module):
1339
+ if not isinstance(student, dspy.Module):
1342
1340
  return {}
1343
- return {name: COMPONENT_KIND_CODE for name, sub in student.named_parameters() if isinstance(sub, flex_cls)}
1341
+ return {name: COMPONENT_KIND_CODE for name, sub in student.named_parameters() if isinstance(sub, dspy.Flex)}
1344
1342
 
1345
1343
 
1346
1344
  def enrich_from_program(
@@ -59,9 +59,6 @@ and sends the id.
59
59
  `cmpnd programs purge --all` empties the Trash. Nothing restores a purged
60
60
  program. Both ask for confirmation at a terminal and need `--force` anywhere
61
61
  else. A live program is never purged.
62
- A program created by name cannot be purged yet. It stays in the Trash, where
63
- it no longer counts toward a plan's program cap, and `purge --all` answers
64
- how many such programs it kept.
65
62
 
66
63
  A program in the Trash or purged gives up its name. The next
67
64
  `cmpnd programs create`, `cmpnd deploy` or SDK run under that name gets a new
@@ -5,7 +5,7 @@ name = "cmpnd"
5
5
  # it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
6
6
  # hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
7
7
  # this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
8
- version = "0.57.0"
8
+ version = "0.58.0"
9
9
  description = "DSPy observability and deployment SDK for cmpnd"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.11"
@@ -28,7 +28,7 @@ classifiers = [
28
28
  ]
29
29
 
30
30
  dependencies = [
31
- "dspy>=3.1.3",
31
+ "dspy>=3.3.0",
32
32
  # Reached directly by the SDK (cmpnd/optimization.py's poll, cmpnd/datasets.py)
33
33
  # and by the ingest transport this wheel bundles (ingest/cmpnd_ingest), whose
34
34
  # only non-stdlib import it is.
@@ -129,6 +129,33 @@ fake-provider = [
129
129
  [tool.uv.sources]
130
130
  cmpnd-fake-provider = { path = "../fake-provider", editable = true }
131
131
 
132
+ # One group per DSPy version the test matrix runs, so uv.lock locks a whole tree for
133
+ # each and a test leg installs from the lock with only DSPy varying
134
+ # (`scripts/install-test-env.sh`; AGENTS.md, "DSPy versions under test"). Dependency
135
+ # groups never reach the wheel's metadata, so a user's install still takes
136
+ # `dspy>=3.3.0` above. Each group name is `dspy-` and the version with dots turned to
137
+ # dashes.
138
+ [dependency-groups]
139
+ dspy-3-4-1 = ["dspy==3.4.1"]
140
+ dspy-3-4-0 = ["dspy==3.4.0"]
141
+ dspy-3-3-1 = ["dspy==3.3.1"]
142
+ dspy-3-3-0 = ["dspy==3.3.0"]
143
+
144
+ [tool.uv]
145
+ # A plain `uv sync` or `uv run` installs the newest tested DSPy.
146
+ default-groups = ["dspy-3-4-1"]
147
+ # The groups pin different DSPy versions, so uv resolves a separate fork for each.
148
+ # The mcp extra floors dspy at 3.3.1, so it conflicts with the dspy-3-3-0 group.
149
+ conflicts = [
150
+ [
151
+ { group = "dspy-3-4-1" },
152
+ { group = "dspy-3-4-0" },
153
+ { group = "dspy-3-3-1" },
154
+ { group = "dspy-3-3-0" },
155
+ ],
156
+ [{ extra = "mcp" }, { group = "dspy-3-3-0" }],
157
+ ]
158
+
132
159
  [project.scripts]
133
160
  cmpnd = "cmpnd.cli:main"
134
161
 
@@ -141,8 +168,8 @@ Homepage = "https://cmpnd.ai"
141
168
  # the two move together or a release fails at upload. hatchling 1.32.0 stamps
142
169
  # 2.5, and the twine inside the pinned pypa/gh-action-pypi-publish accepts it;
143
170
  # that pairing is what `twine check --strict` in sdk-lint proves on every PR.
144
- # `==` so a backend bump arrives as a Renovate PR that runs that check, rather
145
- # than as a silent resolution on release day.
171
+ # `==` so a backend bump is a reviewed edit here that runs that check, rather
172
+ # than a silent resolution on release day.
146
173
  requires = ["hatchling==1.32.0"]
147
174
  build-backend = "hatchling.build"
148
175
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # Install cmpnd with pip's own resolver and check that the installed package
3
3
  # imports and instruments DSPy. Called by .github/workflows/ci-sdk.yml (the
4
- # sdk-test leg for Python 3.15).
4
+ # sdk-test-py315 job, the sdk-test leg for Python 3.15).
5
5
  #
6
6
  # `pip install cmpnd` is the install PyPI advertises. pip honours the
7
7
  # requires-python upper bounds that uv ignores, so this check fails when no
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env bash
2
+ # Build python-sdk/.venv for one sdk-test leg: the SDK and its dev extra, on one
3
+ # Python, at one DSPy version.
4
+ #
5
+ # CALLED BY: .github/workflows/ci-sdk.yml (sdk-test and sdk-test-py315),
6
+ # .github/workflows/sdk-latest-dependencies.yml (with --latest), `just
7
+ # sdk-test-env` at the repo root, and scripts/test-in-linux.sh.
8
+ #
9
+ # The install reads uv.lock. pyproject.toml declares one dependency group per
10
+ # tested DSPy, named `dspy-` and the version with dots turned to dashes, and the lock
11
+ # holds a whole tree for each. A leg syncs its group's tree exactly, so only DSPy,
12
+ # and whatever that DSPy itself pins, differs between legs. A red leg means the
13
+ # change broke something rather than that an upstream release did. The lock moves only
14
+ # by a reviewed commit: a security upgrade when bin/vulncheck fails on an advisory a
15
+ # bump would fix, and any other upgrade as a deliberate lock bump.
16
+ #
17
+ # --latest resolves every package fresh, with only the Python and DSPy versions
18
+ # pinned, as a user's install today would. With the DSPy version `newest`, it pins no
19
+ # DSPy either, so the install takes the newest release `dspy>=…` admits, as `pip
20
+ # install cmpnd` does. It prints the DSPy it installed. The daily run in
21
+ # sdk-latest-dependencies.yml uses it.
22
+ #
23
+ # Usage: scripts/install-test-env.sh [--latest] <python-version> <dspy-version>
24
+ # e.g. scripts/install-test-env.sh 3.13 3.3.0
25
+ # scripts/install-test-env.sh --latest 3.13 3.4.1
26
+ # scripts/install-test-env.sh --latest 3.14 newest
27
+ set -euo pipefail
28
+
29
+ usage() {
30
+ echo "usage: $0 [--latest] <python-version> <dspy-version>" >&2
31
+ exit 2
32
+ }
33
+
34
+ latest=false
35
+ if [ "${1:-}" = "--latest" ]; then
36
+ latest=true
37
+ shift
38
+ fi
39
+ [ "$#" -eq 2 ] || usage
40
+ python_version=$1
41
+ dspy_version=$2
42
+
43
+ cd "$(dirname "${BASH_SOURCE[0]}")/.."
44
+
45
+ if [ "$latest" = true ]; then
46
+ uv venv --clear --python "$python_version" .venv
47
+ if [ "$dspy_version" = newest ]; then
48
+ uv pip install --python .venv/bin/python -e ".[dev]"
49
+ else
50
+ uv pip install --python .venv/bin/python -e ".[dev]" "dspy==$dspy_version"
51
+ fi
52
+ echo "install-test-env: installed $(uv pip freeze --python .venv/bin/python | grep -i '^dspy==')"
53
+ exit 0
54
+ fi
55
+ if [ "$dspy_version" = newest ]; then
56
+ echo "install-test-env: the DSPy version newest needs --latest. uv.lock locks one tree per tested DSPy, and a locked install names one." >&2
57
+ exit 2
58
+ fi
59
+
60
+ group="dspy-${dspy_version//./-}"
61
+ if ! grep -qE "^$group = " pyproject.toml; then
62
+ echo "install-test-env: pyproject.toml declares no dependency group $group. To test dspy $dspy_version, add $group = [\"dspy==$dspy_version\"] to [dependency-groups] and to the conflicts list in [tool.uv], then run uv lock." >&2
63
+ exit 2
64
+ fi
65
+ # --frozen installs exactly what uv.lock holds and never re-locks. sdk-lint's
66
+ # `uv lock --check` fails when the lock is stale against pyproject.toml.
67
+ uv sync --frozen --extra dev --no-default-groups --group "$group" --python "$python_version"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # Run the SDK suite (or a subset) on Linux, in a container that resolves its own
2
+ # Run the SDK suite (or a subset) on Linux, in a container that installs its own
3
3
  # dependencies.
4
4
  #
5
5
  # The lane exists because some of what this SDK has to get right is only
@@ -16,14 +16,16 @@
16
16
  #
17
17
  # It deliberately does NOT mount the host `.venv`: those wheels are macOS
18
18
  # wheels, and a container reusing them fails in ways that teach you nothing about
19
- # the code. uv resolves fresh inside, which is also what makes this a real answer
20
- # to "would CI see this too". The copy also drops `.pyc` files because their
21
- # embedded source paths may name a worktree that moved or no longer exists.
19
+ # the code. uv installs from uv.lock inside, which is also what makes this a real
20
+ # answer to "would CI see this too". SDK_TEST_DSPY_VERSION picks a DSPy group the
21
+ # way an sdk-test leg does (scripts/install-test-env.sh). The copy also drops
22
+ # `.pyc` files because their embedded source paths may name a worktree that moved
23
+ # or no longer exists.
22
24
  #
23
25
  # Usage — everything, or a pytest selector:
24
26
  # python-sdk/scripts/test-in-linux.sh
25
27
  # python-sdk/scripts/test-in-linux.sh tests/test_exporter_queue.py -v
26
- # SDK_TEST_DSPY_VERSION=3.1.3 python-sdk/scripts/test-in-linux.sh tests/test_run_attribution_paths.py -v
28
+ # SDK_TEST_DSPY_VERSION=3.3.0 python-sdk/scripts/test-in-linux.sh tests/test_run_attribution_paths.py -v
27
29
  #
28
30
  # Called by: `just sdk-test-linux` (repo root). No CI workflow — CI already runs
29
31
  # on Linux; this is the local mirror of what it does.
@@ -53,8 +55,7 @@ cp -r /repo/python-sdk /repo/fake-provider /repo/docs /work/
53
55
  rm -rf /work/python-sdk/.venv
54
56
  find /work/python-sdk -name "*.pyc" -delete
55
57
  if [ -n "$SDK_TEST_DSPY_VERSION" ]; then
56
- uv venv --python 3.12 --quiet
57
- uv pip install --quiet -e ".[dev]" "dspy==$SDK_TEST_DSPY_VERSION"
58
+ scripts/install-test-env.sh 3.12 "$SDK_TEST_DSPY_VERSION"
58
59
  else
59
60
  uv sync --extra dev --quiet
60
61
  fi
@@ -19,6 +19,7 @@ import gzip
19
19
  import hashlib
20
20
  import json
21
21
  import re
22
+ import tomllib
22
23
  import uuid
23
24
  from datetime import datetime, timedelta, timezone
24
25
  from pathlib import Path
@@ -109,13 +110,18 @@ def render(doc: dict[str, Any]) -> str:
109
110
  return json.dumps(doc, sort_keys=True, ensure_ascii=False, separators=(",", ":")) + "\n"
110
111
 
111
112
 
112
- def locked_dspy_version() -> str:
113
- """The DSPy version ``python-sdk/uv.lock`` pins, which rendered the fixture's prompts."""
114
- lock = (Path(__file__).resolve().parents[1] / "uv.lock").read_text()
115
- match = re.search(r'\[\[package\]\]\nname = "dspy"\nversion = "([^"]+)"', lock)
116
- if match is None:
117
- raise RuntimeError("uv.lock pins no dspy version")
118
- return match.group(1)
113
+ def default_dspy_version() -> str:
114
+ """The DSPy version a plain ``uv sync`` installs, which rendered the fixture's prompts.
115
+
116
+ That is the version pyproject.toml's default dependency group pins.
117
+ """
118
+ pyproject = tomllib.loads((Path(__file__).resolve().parents[1] / "pyproject.toml").read_text())
119
+ (group,) = pyproject["tool"]["uv"]["default-groups"]
120
+ (requirement,) = pyproject["dependency-groups"][group]
121
+ name, _, version = requirement.partition("==")
122
+ if name != "dspy" or not version:
123
+ raise RuntimeError(f"default group {group} pins no dspy version: {requirement!r}")
124
+ return version
119
125
 
120
126
 
121
127
  def read_committed() -> str:
@@ -14,20 +14,14 @@ import pytest
14
14
  pytest.importorskip("dspy")
15
15
 
16
16
  import dspy
17
+ from dspy.adapters.baml_adapter import BAMLAdapter
17
18
  from dspy.utils.dummies import DummyLM
18
19
 
19
20
  from cmpnd.configuration import configure
20
21
  from cmpnd.context import clear_context, get_current_span
21
22
  from tests import _traced_run
22
23
 
23
- try:
24
- from dspy.adapters.baml_adapter import BAMLAdapter
25
- except ImportError: # pragma: no cover - older DSPy without BAML
26
- BAMLAdapter = None
27
-
28
- ADAPTERS = [dspy.ChatAdapter, dspy.JSONAdapter, dspy.XMLAdapter]
29
- if BAMLAdapter is not None:
30
- ADAPTERS.append(BAMLAdapter)
24
+ ADAPTERS = [dspy.ChatAdapter, dspy.JSONAdapter, dspy.XMLAdapter, BAMLAdapter]
31
25
 
32
26
 
33
27
  @pytest.fixture(autouse=True)
@@ -37,10 +37,8 @@ pytest.importorskip("dspy")
37
37
  def _typed_lm_types_available() -> bool:
38
38
  """Report whether the installed DSPy ships the typed LM contract.
39
39
 
40
- ``dspy.core.types`` (``LMUsage``, ``LMResponse``) arrived in DSPy 3.3.0.
41
- Measured across the versions ``.github/workflows/ci-sdk.yml`` pins: absent on
42
- 3.1.3, 3.2.0 and 3.2.1, present on 3.3.0 and 3.3.1, and removed in 3.4.0b1,
43
- whose ``dspy.core.types`` raises ``ImportError``. Probed by import rather
40
+ ``dspy.core.types`` (``LMUsage``, ``LMResponse``) is present on DSPy 3.3.0 and
41
+ 3.3.1 and removed in 3.4.0b1, whose ``dspy.core.types`` raises ``ImportError``. Probed by import rather
44
42
  than by version number, so the answer stays right whatever the matrix pins
45
43
  next.
46
44
 
@@ -105,11 +105,10 @@ def test_loaded_tag_feeds_compiled_from(tmp_path):
105
105
 
106
106
 
107
107
  def test_wrappers_forward_only_callers_args():
108
- # The patch is installed process-wide, and dump_state/load_state signatures
109
- # differ across DSPy versions (allow_unsafe_lm_state postdates 3.1.x). The
110
- # wrappers must forward only what the caller passed — a bare positional
111
- # round-trip must not raise from an injected keyword. Guards the 3.1.3 CI
112
- # break where the wrapper forced allow_unsafe_lm_state.
108
+ # The patch is installed process-wide, so the wrappers must forward only what
109
+ # the caller passed, whatever dump_state/load_state signature the installed
110
+ # DSPy has: a bare positional round-trip must not raise from an injected
111
+ # keyword such as allow_unsafe_lm_state.
113
112
  prog = _Tiny()
114
113
  state = prog.dump_state() # no json_mode kwarg
115
114
  _Tiny().load_state(state) # no allow_unsafe_lm_state kwarg
@@ -7,6 +7,7 @@ active cmpnd callback while preserving the func's signature (the interpreter
7
7
  builds its sandbox stub from inspect.signature).
8
8
  """
9
9
 
10
+ import contextlib
10
11
  import inspect
11
12
  import uuid
12
13
 
@@ -23,6 +24,18 @@ def _configured():
23
24
  yield
24
25
 
25
26
 
27
+ @pytest.fixture
28
+ def use_callbacks():
29
+ """Installs DSPy callbacks for the rest of one test through dspy.context.
30
+
31
+ monkeypatch cannot set them: dspy.settings serves callbacks from its config
32
+ through __getattr__, so pytest 9.2's monkeypatch records the attribute as
33
+ unset and its teardown delattr fails.
34
+ """
35
+ with contextlib.ExitStack() as stack:
36
+ yield lambda *cbs: stack.enter_context(dspy.context(callbacks=list(cbs)))
37
+
38
+
26
39
  def _make_rlm():
27
40
  def add_pages(first: int, last: int) -> int:
28
41
  """Sum a page range."""
@@ -52,7 +65,7 @@ def test_wrapped_tool_preserves_signature():
52
65
  assert inspect.signature(shim) == inspect.signature(add_pages)
53
66
 
54
67
 
55
- def test_tool_span_created_and_nested_under_rlm(monkeypatch):
68
+ def test_tool_span_created_and_nested_under_rlm(monkeypatch, use_callbacks):
56
69
  """With a callback and an RLM.forward span on the stack, invoking a wrapped
57
70
  tool creates a TOOL span parented to the RLM span."""
58
71
  _rlm_patch._patched = False
@@ -61,7 +74,7 @@ def test_tool_span_created_and_nested_under_rlm(monkeypatch):
61
74
  tracked = []
62
75
  cb = callback.CmpndCallback()
63
76
  monkeypatch.setattr(cb, "_track_span", lambda span: tracked.append(span))
64
- monkeypatch.setattr(dspy.settings, "callbacks", [cb], raising=False)
77
+ use_callbacks(cb)
65
78
 
66
79
  context.clear_context()
67
80
  context.set_current_trace(models.TraceBuilder(trace_id=uuid.uuid4()))
@@ -86,7 +99,7 @@ def test_tool_span_created_and_nested_under_rlm(monkeypatch):
86
99
  assert span.trace_id == rlm_span.trace_id
87
100
 
88
101
 
89
- def test_multiple_callbacks_emit_one_tool_span(monkeypatch):
102
+ def test_multiple_callbacks_emit_one_tool_span(monkeypatch, use_callbacks):
90
103
  """Two registered CmpndCallbacks share one span-stack contextvar, so the
91
104
  shim dispatches to only the first — one tool span, stack balanced, no
92
105
  tool-span-nested-under-tool-span corruption."""
@@ -98,7 +111,7 @@ def test_multiple_callbacks_emit_one_tool_span(monkeypatch):
98
111
  cb_b = callback.CmpndCallback()
99
112
  monkeypatch.setattr(cb_a, "_track_span", lambda span: tracked_a.append(span))
100
113
  monkeypatch.setattr(cb_b, "_track_span", lambda span: tracked_b.append(span))
101
- monkeypatch.setattr(dspy.settings, "callbacks", [cb_a, cb_b], raising=False)
114
+ use_callbacks(cb_a, cb_b)
102
115
 
103
116
  context.clear_context()
104
117
  context.set_current_trace(models.TraceBuilder(trace_id=uuid.uuid4()))
@@ -136,14 +149,14 @@ def test_tracing_off_calls_func_without_span():
136
149
  dspy.settings.callbacks = original
137
150
 
138
151
 
139
- def test_raising_tool_closes_span_and_reraises(monkeypatch):
152
+ def test_raising_tool_closes_span_and_reraises(monkeypatch, use_callbacks):
140
153
  _rlm_patch._patched = False
141
154
  _rlm_patch.patch_rlm_tools()
142
155
 
143
156
  tracked = []
144
157
  cb = callback.CmpndCallback()
145
158
  monkeypatch.setattr(cb, "_track_span", lambda span: tracked.append(span))
146
- monkeypatch.setattr(dspy.settings, "callbacks", [cb], raising=False)
159
+ use_callbacks(cb)
147
160
 
148
161
  def boom(x: int) -> int:
149
162
  raise ValueError("nope")
@@ -350,12 +350,12 @@ def test_the_committed_thirty_turn_fixture_is_what_the_sdk_emits():
350
350
  """serve's Postgres test ingests this file, so it must be the SDK's current output.
351
351
 
352
352
  The rendered prompts are DSPy's text, so the comparison holds only on the
353
- DSPy the lockfile pins; the CI matrix's other versions skip it.
353
+ DSPy the default dependency group pins; the CI matrix's other versions skip it.
354
354
  """
355
355
  from tests import span_reference_fixture
356
356
 
357
- if dspy.__version__ != span_reference_fixture.locked_dspy_version():
358
- pytest.skip(f"the fixture was rendered by the locked DSPy, not {dspy.__version__}")
357
+ if dspy.__version__ != span_reference_fixture.default_dspy_version():
358
+ pytest.skip(f"the fixture was rendered by the default group's DSPy, not {dspy.__version__}")
359
359
  fresh = span_reference_fixture.render(span_reference_fixture.build())
360
360
  assert span_reference_fixture.read_committed() == fresh, (
361
361
  "docs/schemas/span-references/rlm-30-turns.json.gz is stale; "