cmpnd 0.80.0__tar.gz → 0.81.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 (405) hide show
  1. {cmpnd-0.80.0 → cmpnd-0.81.0}/PKG-INFO +4 -1
  2. {cmpnd-0.80.0 → cmpnd-0.81.0}/README.md +3 -0
  3. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/__init__.py +2 -1
  4. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/client.py +3 -0
  5. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment_runs.py +70 -22
  6. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/execution.py +3 -1
  7. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/sdk-instrumentation.md +14 -2
  8. {cmpnd-0.80.0 → cmpnd-0.81.0}/pyproject.toml +1 -1
  9. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployment_runs.py +89 -0
  10. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_execute.py +31 -0
  11. {cmpnd-0.80.0 → cmpnd-0.81.0}/uv.lock +1 -1
  12. {cmpnd-0.80.0 → cmpnd-0.81.0}/.gitignore +0 -0
  13. {cmpnd-0.80.0 → cmpnd-0.81.0}/AGENTS.md +0 -0
  14. {cmpnd-0.80.0 → cmpnd-0.81.0}/CLAUDE.md +0 -0
  15. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_assessments.py +0 -0
  16. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_authored_import.py +0 -0
  17. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_deployments.py +0 -0
  18. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_exporter_pool.py +0 -0
  19. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_gepa_patch.py +0 -0
  20. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_http.py +0 -0
  21. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_program_patch.py +0 -0
  22. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_rlm_patch.py +0 -0
  23. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_runtime_tools.py +0 -0
  24. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_timespec.py +0 -0
  25. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_traces.py +0 -0
  26. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/_valsets.py +0 -0
  27. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/authored.py +0 -0
  28. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/callback.py +0 -0
  29. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/__init__.py +0 -0
  30. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/api_client.py +0 -0
  31. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/__init__.py +0 -0
  32. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/admin.py +0 -0
  33. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/assessments.py +0 -0
  34. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/auth.py +0 -0
  35. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/datasets.py +0 -0
  36. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/deployments.py +0 -0
  37. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/evals.py +0 -0
  38. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/login.py +0 -0
  39. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/optimizations.py +0 -0
  40. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/org.py +0 -0
  41. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/programs.py +0 -0
  42. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  43. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  44. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/top.py +0 -0
  45. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/traces.py +0 -0
  46. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/commands/valsets.py +0 -0
  47. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/credentials.py +0 -0
  48. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/deprecation.py +0 -0
  49. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/pagination.py +0 -0
  50. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/shell.py +0 -0
  51. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/trace_render.py +0 -0
  52. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/tree_help.py +0 -0
  53. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/verbs.py +0 -0
  54. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/cli/views.py +0 -0
  55. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/configuration.py +0 -0
  56. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/context.py +0 -0
  57. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/credentials.py +0 -0
  58. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/dataset_sync.py +0 -0
  59. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/datasets.py +0 -0
  60. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/decorators.py +0 -0
  61. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment.py +0 -0
  62. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/deployment_metadata.py +0 -0
  63. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/eval_handler.py +0 -0
  64. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/exporter.py +0 -0
  65. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/exporter_http.py +0 -0
  66. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/helpers.py +0 -0
  67. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/identity.py +0 -0
  68. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/imaging.py +0 -0
  69. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/__init__.py +0 -0
  70. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/decode.py +0 -0
  71. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/encode.py +0 -0
  72. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/hash.py +0 -0
  73. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/program.py +0 -0
  74. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/reflection.py +0 -0
  75. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/types.py +0 -0
  76. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/ir/xxh64.py +0 -0
  77. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/lm_configuration.py +0 -0
  78. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/mcp_servers.py +0 -0
  79. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/models.py +0 -0
  80. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/named_programs.py +0 -0
  81. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimization.py +0 -0
  82. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/__init__.py +0 -0
  83. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/gepa.py +0 -0
  84. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  85. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/resume.py +0 -0
  86. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/optimizers/tracker.py +0 -0
  87. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/packaging.py +0 -0
  88. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/program_naming.py +0 -0
  89. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/programs.py +0 -0
  90. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/references.py +0 -0
  91. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/retry.py +0 -0
  92. {cmpnd-0.80.0 → cmpnd-0.81.0}/cmpnd/traces.py +0 -0
  93. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/2026-04-02-code-review.md +0 -0
  94. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/cli.md +0 -0
  95. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/client.md +0 -0
  96. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/custom-proposer.md +0 -0
  97. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  98. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  99. {cmpnd-0.80.0 → cmpnd-0.81.0}/docs/reading-traces.md +0 -0
  100. {cmpnd-0.80.0 → cmpnd-0.81.0}/examples/generalizing_proposer.py +0 -0
  101. {cmpnd-0.80.0 → cmpnd-0.81.0}/examples/local_ollama.py +0 -0
  102. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/LINEAGE.md +0 -0
  103. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/README.md +0 -0
  104. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  105. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  106. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  107. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  108. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  109. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  110. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/py.typed +0 -0
  111. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  112. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/retry.py +0 -0
  113. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  114. {cmpnd-0.80.0 → cmpnd-0.81.0}/ingest/pyproject.toml +0 -0
  115. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/audit-sdist.sh +0 -0
  116. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/capture_review_run.py +0 -0
  117. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/check-pip-install.sh +0 -0
  118. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/check_release_artifacts.py +0 -0
  119. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/fixtures/review_run.json.gz +0 -0
  120. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/gepa_resume_bug.py +0 -0
  121. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/install-test-env.sh +0 -0
  122. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/release-gate.sh +0 -0
  123. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/release-real-models.sh +0 -0
  124. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/require_version_bump.py +0 -0
  125. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/seed_review_run.py +0 -0
  126. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/selfhost_compat.py +0 -0
  127. {cmpnd-0.80.0 → cmpnd-0.81.0}/scripts/test-in-linux.sh +0 -0
  128. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/__init__.pyi +0 -0
  129. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  130. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  131. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/__init__.pyi +0 -0
  132. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/callback.pyi +0 -0
  133. {cmpnd-0.80.0 → cmpnd-0.81.0}/stubs/dspy/utils/dummies.pyi +0 -0
  134. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/__init__.py +0 -0
  135. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_credential_route.py +0 -0
  136. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_deployment_signature_helpers.py +0 -0
  137. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_exporter_helpers.py +0 -0
  138. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_fake_clock.py +0 -0
  139. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_identity_helpers.py +0 -0
  140. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_resolve_refs.py +0 -0
  141. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/_traced_run.py +0 -0
  142. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/conftest.py +0 -0
  143. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/__init__.py +0 -0
  144. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/committee_task.py +0 -0
  145. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/conftest.py +0 -0
  146. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/continuation_task.py +0 -0
  147. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  148. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  149. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/fake_lm.py +0 -0
  150. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/helpers.py +0 -0
  151. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/target_capabilities.py +0 -0
  152. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_assessments_cli.py +0 -0
  153. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_capture_prompts.py +0 -0
  154. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_composite_module.py +0 -0
  155. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  156. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_execute.py +0 -0
  157. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_pandas.py +0 -0
  158. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_deploy_programs.py +0 -0
  159. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_edge_cases.py +0 -0
  160. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_example_hash.py +0 -0
  161. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_gepa_optimization.py +0 -0
  162. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_interpreter_spans.py +0 -0
  163. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_lm_accuracy.py +0 -0
  164. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_module_tracing.py +0 -0
  165. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimization_lineage.py +0 -0
  166. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  167. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
  168. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_continuation.py +0 -0
  169. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
  170. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_failures.py +0 -0
  171. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_loop.py +0 -0
  172. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  173. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  174. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_parallel_export.py +0 -0
  175. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_project_attribution.py +0 -0
  176. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_react_tool_spans.py +0 -0
  177. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_save_load.py +0 -0
  178. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_trace_structure.py +0 -0
  179. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_traces_read.py +0 -0
  180. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_user_attribution.py +0 -0
  181. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/e2e/test_valsets_cli.py +0 -0
  182. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  183. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  184. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  185. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  186. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  187. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  188. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  189. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  190. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  191. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/10_react.json +0 -0
  192. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/11_refine.json +0 -0
  193. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/12_retrieve.json +0 -0
  194. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/13_knn.json +0 -0
  195. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/14_parallel.json +0 -0
  196. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/identity_vectors/README.md +0 -0
  197. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/ingest_conformance.py +0 -0
  198. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/__init__.py +0 -0
  199. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/authored_optimize/judge.py +0 -0
  200. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  201. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/conftest.py +0 -0
  202. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  203. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/hosted_optimize_probe.py +0 -0
  204. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/optimization_run_probe.py +0 -0
  205. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  206. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_logs_renders_traces.py +0 -0
  207. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_optimization_run.py +0 -0
  208. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_optimizing_progress.py +0 -0
  209. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/integration/test_unhappy_path.py +0 -0
  210. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/__init__.py +0 -0
  211. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/__main__.py +0 -0
  212. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/drain.py +0 -0
  213. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/ingest.py +0 -0
  214. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/latency_transport.py +0 -0
  215. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/rlm_shape.py +0 -0
  216. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/rlm_size_report.py +0 -0
  217. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/sweep.py +0 -0
  218. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/test_rlm_shape.py +0 -0
  219. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/load/test_rlm_size_report.py +0 -0
  220. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/__init__.py +0 -0
  221. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/conftest.py +0 -0
  222. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/seed_parity.py +0 -0
  223. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_auth.py +0 -0
  224. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_datasets.py +0 -0
  225. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_deployments.py +0 -0
  226. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_evals.py +0 -0
  227. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_health.py +0 -0
  228. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_modules.py +0 -0
  229. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_optimizations.py +0 -0
  230. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_programs.py +0 -0
  231. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_signatures.py +0 -0
  232. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_trace_streaming.py +0 -0
  233. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/parity/test_traces.py +0 -0
  234. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/__init__.py +0 -0
  235. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_provider.py +0 -0
  236. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_readiness.py +0 -0
  237. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_reliability.py +0 -0
  238. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/_result.py +0 -0
  239. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/mint_bedrock_token.py +0 -0
  240. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_bedrock_converse.py +0 -0
  241. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_deploy_programs.py +0 -0
  242. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_multi_client_stress.py +0 -0
  243. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_client_committee.py +0 -0
  244. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_continuation.py +0 -0
  245. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_loop.py +0 -0
  246. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
  247. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_optimize_stress.py +0 -0
  248. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_provider_roles.py +0 -0
  249. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_readiness.py +0 -0
  250. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_real_provider_twins.py +0 -0
  251. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_reliability.py +0 -0
  252. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_reliability_classify.py +0 -0
  253. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_rlm_wasm.py +0 -0
  254. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/real_models/test_trace_search.py +0 -0
  255. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/span_reference_fixture.py +0 -0
  256. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_adapter_reentrancy.py +0 -0
  257. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_assessments_api.py +0 -0
  258. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored.py +0 -0
  259. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_binding_credentials.py +0 -0
  260. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_bundle_collisions.py +0 -0
  261. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_metric_contract.py +0 -0
  262. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_named_models.py +0 -0
  263. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_authored_optimize.py +0 -0
  264. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_callback.py +0 -0
  265. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_candidate_lineage.py +0 -0
  266. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/__init__.py +0 -0
  267. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/conftest.py +0 -0
  268. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_admin.py +0 -0
  269. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_api_client.py +0 -0
  270. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_assessments.py +0 -0
  271. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_auth.py +0 -0
  272. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_credentials.py +0 -0
  273. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_datasets.py +0 -0
  274. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_deployment_runs.py +0 -0
  275. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_deployments.py +0 -0
  276. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_evals.py +0 -0
  277. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_login.py +0 -0
  278. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_main.py +0 -0
  279. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_optimizations.py +0 -0
  280. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_org.py +0 -0
  281. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_pagination.py +0 -0
  282. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_parity.py +0 -0
  283. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_programs.py +0 -0
  284. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_provider_credentials.py +0 -0
  285. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_schema_sample.py +0 -0
  286. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_shell.py +0 -0
  287. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_tool_servers.py +0 -0
  288. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_top.py +0 -0
  289. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces.py +0 -0
  290. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
  291. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  292. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_tree_help.py +0 -0
  293. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cli/test_valsets.py +0 -0
  294. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client.py +0 -0
  295. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client_floor.py +0 -0
  296. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_client_program_names.py +0 -0
  297. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/__init__.py +0 -0
  298. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/conftest.py +0 -0
  299. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_edge_cases.py +0 -0
  300. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  301. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_clustering/test_type_conversion.py +0 -0
  302. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_cmp551_grouping_identity.py +0 -0
  303. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_configuration.py +0 -0
  304. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_context.py +0 -0
  305. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_context_propagation.py +0 -0
  306. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_kwargs.py +0 -0
  307. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_selection.py +0 -0
  308. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_credential_values.py +0 -0
  309. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_dataset_polling.py +0 -0
  310. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_dataset_sync.py +0 -0
  311. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_datasets.py +0 -0
  312. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_decision_client_spans.py +0 -0
  313. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_decorators.py +0 -0
  314. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy.py +0 -0
  315. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy_mcp_tool_references.py +0 -0
  316. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deploy_program_id.py +0 -0
  317. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployment_metadata.py +0 -0
  318. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_deployments_read.py +0 -0
  319. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval.py +0 -0
  320. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_example_attribution.py +0 -0
  321. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_program_id.py +0 -0
  322. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_start.py +0 -0
  323. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_eval_trace_grouping.py +0 -0
  324. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exception_paths.py +0 -0
  325. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_execute_run_identity.py +0 -0
  326. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter.py +0 -0
  327. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_program_names.py +0 -0
  328. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_queue.py +0 -0
  329. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_exporter_real.py +0 -0
  330. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_fake_lm.py +0 -0
  331. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_callback.py +0 -0
  332. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_integration.py +0 -0
  333. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_output_normalization.py +0 -0
  334. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_gepa_resume.py +0 -0
  335. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_identity.py +0 -0
  336. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_imaging.py +0 -0
  337. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_import_weight.py +0 -0
  338. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ingest_conformance.py +0 -0
  339. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ingest_second_producer.py +0 -0
  340. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_integration.py +0 -0
  341. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_interpreter_callback.py +0 -0
  342. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_encoder_properties.py +0 -0
  343. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_golden_vectors.py +0 -0
  344. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_ir_roundtrip.py +0 -0
  345. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm15_native_calls.py +0 -0
  346. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm_configuration.py +0 -0
  347. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_lm_usage_shapes.py +0 -0
  348. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_mcp_tools.py +0 -0
  349. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_models.py +0 -0
  350. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_multi_client_stress_readiness.py +0 -0
  351. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_no_signature_hash_on_the_wire.py +0 -0
  352. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_phase_callback.py +0 -0
  353. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_program_names.py +0 -0
  354. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_progress.py +0 -0
  355. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimization_start.py +0 -0
  356. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize.py +0 -0
  357. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_budget.py +0 -0
  358. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_lift.py +0 -0
  359. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_lms.py +0 -0
  360. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_proposer.py +0 -0
  361. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_reflection_lm.py +0 -0
  362. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_optimize_terminal_failure.py +0 -0
  363. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging.py +0 -0
  364. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_callable_source.py +0 -0
  365. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_mcp_tools.py +0 -0
  366. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_packaging_program_source.py +0 -0
  367. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_poll_until.py +0 -0
  368. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_id_deprecation.py +0 -0
  369. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_identity.py +0 -0
  370. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_lineage_persist.py +0 -0
  371. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_names_in_deploy.py +0 -0
  372. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_program_naming.py +0 -0
  373. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_programs_create.py +0 -0
  374. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_project_payload.py +0 -0
  375. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_real_provider_twins_readiness.py +0 -0
  376. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reflector_properties.py +0 -0
  377. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reflector_smoke.py +0 -0
  378. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_release_gate_script.py +0 -0
  379. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_release_real_models_script.py +0 -0
  380. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_replaced_names.py +0 -0
  381. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_repro_reactv2_bugs.py +0 -0
  382. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_require_version_bump.py +0 -0
  383. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_retry.py +0 -0
  384. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_reversible_failures.py +0 -0
  385. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_rlm_patch.py +0 -0
  386. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_run_attribution_paths.py +0 -0
  387. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_runtime_tools.py +0 -0
  388. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_schemas.py +0 -0
  389. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_seal_lm_credential.py +0 -0
  390. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_seed_review_run.py +0 -0
  391. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_signature_inputs.py +0 -0
  392. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_span_references.py +0 -0
  393. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_span_sent_once.py +0 -0
  394. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_system_one.py +0 -0
  395. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_context_concurrency.py +0 -0
  396. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_fact_wire_contract.py +0 -0
  397. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_facts.py +0 -0
  398. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_trace_render.py +0 -0
  399. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_traces_read.py +0 -0
  400. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_tracked_gepa.py +0 -0
  401. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_tracker_enrich.py +0 -0
  402. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_truncation.py +0 -0
  403. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_upload_auth_headers.py +0 -0
  404. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_valsets_api.py +0 -0
  405. {cmpnd-0.80.0 → cmpnd-0.81.0}/tests/test_xxh64.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.80.0
3
+ Version: 0.81.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>
@@ -722,6 +722,9 @@ errors:
722
722
 
723
723
  - A refused request raises `httpx.HTTPStatusError`.
724
724
  - A lost or failed submission reply raises `RunSubmissionUncertain`.
725
+ - A connection to the platform that never opened, such as one refused, raises
726
+ `RunNotSubmitted` after a few attempts. It names the endpoint, and nothing was
727
+ sent, so submitting again is safe. It is a `RunSubmissionUncertain`.
725
728
  - A spent budget raises `RunWaitTimeout`, which holds the run ID.
726
729
  - An answer that expired before it was read raises `RunResultExpired`.
727
730
 
@@ -671,6 +671,9 @@ errors:
671
671
 
672
672
  - A refused request raises `httpx.HTTPStatusError`.
673
673
  - A lost or failed submission reply raises `RunSubmissionUncertain`.
674
+ - A connection to the platform that never opened, such as one refused, raises
675
+ `RunNotSubmitted` after a few attempts. It names the endpoint, and nothing was
676
+ sent, so submitting again is safe. It is a `RunSubmissionUncertain`.
674
677
  - A spent budget raises `RunWaitTimeout`, which holds the run ID.
675
678
  - An answer that expired before it was read raises `RunResultExpired`.
676
679
 
@@ -37,7 +37,7 @@ from .deployment_metadata import (
37
37
  DeploymentSignatureResponse,
38
38
  UnsupportedDeploymentMetadataVersion,
39
39
  )
40
- from .deployment_runs import RunResultExpired, RunSubmissionUncertain, RunWaitTimeout
40
+ from .deployment_runs import RunNotSubmitted, RunResultExpired, RunSubmissionUncertain, RunWaitTimeout
41
41
  from .execution import DeployedProgram, RetryableProviderError
42
42
  from .exporter import flush_exporter, shutdown_exporter
43
43
  from .lm_configuration import HostedLM, SystemOne, configure_lm
@@ -120,6 +120,7 @@ __all__ = [
120
120
  "DeploymentMetadataError",
121
121
  "UnsupportedDeploymentMetadataVersion",
122
122
  "RunSubmissionUncertain",
123
+ "RunNotSubmitted",
123
124
  "RunWaitTimeout",
124
125
  "RunResultExpired",
125
126
  "DeployedProgram",
@@ -360,6 +360,9 @@ class Client:
360
360
  failure. No run is started again automatically.
361
361
  RunSubmissionUncertain: If the POST reply was lost or was a server
362
362
  error, so serve may have accepted the run.
363
+ RunNotSubmitted: If no connection to serve opened, after a few
364
+ attempts inside the budget. Nothing was sent. It is a
365
+ ``RunSubmissionUncertain``.
363
366
  RunWaitTimeout: If the run has not settled within the local budget.
364
367
  The run continues.
365
368
  RunResultExpired: If the retained answer expired before it was read.
@@ -1,9 +1,10 @@
1
1
  """Durable deployment run submission, discovery, and result retrieval.
2
2
 
3
- Submission sends one POST and never repeats it. A lost or failed reply may hide
4
- an accepted run, so callers inspect the run list before deciding whether to
5
- submit new work. Waiting reads the accepted run's status and result routes,
6
- retrying those reads inside one local budget.
3
+ Submission sends one POST and never repeats it once a connection opened. A lost or
4
+ failed reply may hide an accepted run, so callers inspect the run list before
5
+ deciding whether to submit new work. A connection that never opened sent nothing,
6
+ so the POST is tried again a few times inside the local budget. Waiting reads the
7
+ accepted run's status and result routes, retrying those reads inside one local budget.
7
8
  """
8
9
 
9
10
  from __future__ import annotations
@@ -40,6 +41,11 @@ _UNBOUNDED_POST_READ = 60.0
40
41
  # retried rather than consuming the whole budget.
41
42
  _READ_TIMEOUT = 30.0
42
43
  _FIRST_POLL_DELAY = 0.5
44
+ # Attempts to open the POST's connection, and the first pause between them, which
45
+ # doubles. A connection that never opened sent nothing, so another attempt cannot
46
+ # submit a second run.
47
+ _CONNECT_ATTEMPTS = 3
48
+ _FIRST_CONNECT_DELAY = 0.5
43
49
  _MAX_POLL_DELAY = 5.0
44
50
  # A server poll hint is honored up to this many seconds.
45
51
  _MAX_RETRY_AFTER = 60.0
@@ -100,6 +106,30 @@ class RunSubmissionUncertain(RuntimeError):
100
106
  _set_run_id(self, run_id)
101
107
 
102
108
 
109
+ class RunNotSubmitted(RunSubmissionUncertain):
110
+ """No connection to serve opened, so the POST sent nothing and no run exists.
111
+
112
+ ``endpoint`` is the address the SDK could not connect to, and the message gives
113
+ the transport's reason, such as a refused connection. Submitting again is safe.
114
+
115
+ A ``RunSubmissionUncertain`` so a caller that handles the uncertain outcome
116
+ still catches it. Its recovery, inspecting the run list before submitting
117
+ again, is unnecessary here but never wrong.
118
+ """
119
+
120
+ def __init__(self, deployment_id: str, endpoint: str, *, attempts: int, cause: BaseException):
121
+ reason = str(cause) or type(cause).__name__
122
+ RuntimeError.__init__(
123
+ self,
124
+ f"Deployment {deployment_id} was not submitted: no connection to {endpoint} opened "
125
+ f"in {attempts} attempt(s) ({reason}). Nothing was sent, so submitting again is safe.",
126
+ )
127
+ self.deployment_id = deployment_id
128
+ self.endpoint = endpoint
129
+ self.status_code = None
130
+ _set_run_id(self, None)
131
+
132
+
103
133
  def _cancel_command(run_id: str) -> str:
104
134
  return f"cmpnd deployments runs cancel {run_id}"
105
135
 
@@ -387,24 +417,42 @@ class _RunClient:
387
417
  return response
388
418
 
389
419
  def submit(self, deployment_id: str, body: dict[str, Any], deadline: float | None, *, wait: bool) -> dict[str, Any]:
390
- """Send the one POST. Never retried: a repeat would be a second paid run."""
391
- remaining = _remaining(deadline)
392
- if remaining is not None and remaining <= 0:
393
- raise TimeoutError(f"The local budget ran out before deployment {deployment_id} was submitted")
394
- prefer = server_wait(remaining) if wait else 0
395
- # The read timeout outlasts the server wait, so the transport never gives
396
- # up while serve is still holding an accepted run's reply.
397
- read_timeout = remaining if remaining is not None else prefer + _UNBOUNDED_POST_READ
398
- try:
399
- response = self._send(
400
- "POST",
401
- f"/api/v1/deployments/{deployment_id}/runs",
402
- timeout=read_timeout,
403
- body=body,
404
- headers={"Prefer": f"wait={prefer}"} if prefer > 0 else None,
405
- )
406
- except httpx.RequestError as exc:
407
- raise RunSubmissionUncertain(deployment_id) from exc
420
+ """Send the one POST.
421
+
422
+ Never repeated once a connection opened: a repeat would be a second paid run. A
423
+ connection that never opened sent nothing, so it is attempted again while the
424
+ budget allows, and then raises ``RunNotSubmitted``.
425
+ """
426
+ attempt = 0
427
+ while True:
428
+ attempt += 1
429
+ remaining = _remaining(deadline)
430
+ if remaining is not None and remaining <= 0:
431
+ raise TimeoutError(f"The local budget ran out before deployment {deployment_id} was submitted")
432
+ prefer = server_wait(remaining) if wait else 0
433
+ # The read timeout outlasts the server wait, so the transport never gives
434
+ # up while serve is still holding an accepted run's reply.
435
+ read_timeout = remaining if remaining is not None else prefer + _UNBOUNDED_POST_READ
436
+ try:
437
+ response = self._send(
438
+ "POST",
439
+ f"/api/v1/deployments/{deployment_id}/runs",
440
+ timeout=read_timeout,
441
+ body=body,
442
+ headers={"Prefer": f"wait={prefer}"} if prefer > 0 else None,
443
+ )
444
+ break
445
+ # httpx raises these two only while it opens a connection, before any byte
446
+ # of the request is written. Every other transport error may follow a sent
447
+ # request, so it leaves acceptance uncertain.
448
+ except (httpx.ConnectError, httpx.ConnectTimeout) as exc:
449
+ pause = _jitter(_FIRST_CONNECT_DELAY * 2 ** (attempt - 1))
450
+ left = _remaining(deadline)
451
+ if attempt >= _CONNECT_ATTEMPTS or (left is not None and left <= pause):
452
+ raise RunNotSubmitted(deployment_id, self.endpoint, attempts=attempt, cause=exc) from exc
453
+ _sleep(pause)
454
+ except httpx.RequestError as exc:
455
+ raise RunSubmissionUncertain(deployment_id) from exc
408
456
  if response.status_code >= 500:
409
457
  raise RunSubmissionUncertain(
410
458
  deployment_id,
@@ -291,9 +291,11 @@ def _raise_stored_failure(run_id: str, result: object, endpoint: str) -> None:
291
291
  provider_failure = _retryable_provider_failure(response)
292
292
  if provider_failure is not None:
293
293
  provider_status, attempts, retry_after = provider_failure
294
+ # The worker's status says only that the run failed, and the provider's own
295
+ # status is in the detail, so the message leaves the worker's out.
294
296
  raise _with_run_id(
295
297
  RetryableProviderError(
296
- message,
298
+ f"Deployment run {run_id} failed" + (f": {detail}" if detail else ""),
297
299
  request=request,
298
300
  response=response,
299
301
  provider_status=provider_status,
@@ -457,7 +457,15 @@ Serve's not-ready `409` and `422` refusals keep the `RuntimeError` type and
457
457
  message that `run_deployment()` raises, and are `httpx.HTTPStatusError` too. A
458
458
  lost POST reply or a server `5xx` leaves acceptance uncertain, so the SDK raises
459
459
  `RunSubmissionUncertain` with `status_code` set when serve answered. Its message
460
- names the command to list recent runs. Reads that time out or answer `408`,
460
+ names the command to list recent runs. A connection that never opened sent
461
+ nothing: httpx raises `ConnectError` or `ConnectTimeout` only before any byte of
462
+ the request is written. The SDK tries the POST up to three times, pausing about
463
+ half a second and then a second, and stops early when the pause would outlast
464
+ the budget. Then it raises `RunNotSubmitted`, which names the endpoint and the
465
+ transport's reason, such as a refused connection, and says submitting again is
466
+ safe. `RunNotSubmitted` subclasses `RunSubmissionUncertain`, so a handler for the
467
+ uncertain case still catches it. A read timeout, a write failure or a broken
468
+ reply may follow a sent request, so each stays uncertain. Reads that time out or answer `408`,
461
469
  `429` or `5xx` are retried with backoff and jitter, honoring `Retry-After`. A
462
470
  `401`, `403` or `404` read raises at once. A spent budget raises
463
471
  `RunWaitTimeout`, and the accepted run continues. Its `status` and
@@ -477,7 +485,11 @@ the same metadata, for a completed run's prediction and a failed run's error.
477
485
  trace, when the server names none, and when the run failed before serve
478
486
  accepted it. A
479
487
  retained provider failure keeps its structured `RetryableProviderError` type but
480
- does not start another run. Trace delivery can finish after the result is
488
+ does not start another run. Its message is the provider's outage as the egress
489
+ service reported it, such as `Deployment run dr_… failed: the provider at
490
+ gw.lunaroute.com was unavailable: 3 attempt(s) over 3m1.367s; its last answer was
491
+ 503: backend unavailable`. It leaves out the worker's status, which the exception's
492
+ `response` still carries, and the run's `error_code` is `ProviderUnavailable`. Trace delivery can finish after the result is
481
493
  available.
482
494
 
483
495
  Call `client.submit_deployment_run(deployment, inputs)` to accept work without a
@@ -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.80.0"
8
+ version = "0.81.0"
9
9
  description = "DSPy observability and deployment SDK for cmpnd"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.11"
@@ -199,6 +199,95 @@ def test_execute_never_repeats_uncertain_post(monkeypatch: pytest.MonkeyPatch, f
199
199
  assert [req.method for req in seen] == ["POST"]
200
200
 
201
201
 
202
+ @pytest.mark.parametrize(
203
+ ("failure", "cause"),
204
+ [
205
+ (httpx.ConnectError, "[Errno 61] Connection refused"),
206
+ (httpx.ConnectTimeout, "timed out"),
207
+ ],
208
+ )
209
+ def test_a_connection_that_never_opened_submitted_nothing(
210
+ monkeypatch: pytest.MonkeyPatch, failure: type[httpx.TransportError], cause: str
211
+ ):
212
+ seen: list[httpx.Request] = []
213
+
214
+ def answer(req: httpx.Request) -> httpx.Response:
215
+ seen.append(req)
216
+ raise failure(cause, request=req)
217
+
218
+ _transport(monkeypatch, answer)
219
+ _clock(monkeypatch)
220
+ with pytest.raises(deployment_runs.RunNotSubmitted) as caught:
221
+ _client().run_deployment(DEPLOYMENT_ID, question="hi")
222
+ error = caught.value
223
+ assert str(error) == (
224
+ f"Deployment {DEPLOYMENT_ID} was not submitted: no connection to https://example.test opened "
225
+ f"in {len(seen)} attempt(s) ({cause}). Nothing was sent, so submitting again is safe."
226
+ )
227
+ assert error.endpoint == "https://example.test"
228
+ assert error.deployment_id == DEPLOYMENT_ID
229
+ assert error.status_code is None
230
+ assert isinstance(error.__cause__, failure)
231
+ assert _client().deployment_run_id(error) is None
232
+ # A caller that already handles the uncertain outcome still catches it: inspecting
233
+ # the run list before resubmitting is unnecessary here, never wrong.
234
+ assert isinstance(error, deployment_runs.RunSubmissionUncertain)
235
+ assert cmpnd.RunNotSubmitted is deployment_runs.RunNotSubmitted
236
+ assert [req.method for req in seen] == ["POST"] * deployment_runs._CONNECT_ATTEMPTS
237
+
238
+
239
+ def test_a_connection_that_opens_on_a_later_attempt_submits_once(monkeypatch: pytest.MonkeyPatch):
240
+ seen: list[str] = []
241
+
242
+ def answer(req: httpx.Request) -> httpx.Response:
243
+ seen.append(req.method)
244
+ if len(seen) == 1:
245
+ raise httpx.ConnectError("[Errno 61] Connection refused", request=req)
246
+ if req.method == "POST":
247
+ return httpx.Response(200, json=_run("completed", {"output": {"answer": "ready"}}), request=req)
248
+ raise AssertionError(f"unexpected {req.method}")
249
+
250
+ _transport(monkeypatch, answer)
251
+ _clock(monkeypatch)
252
+ assert _client().run_deployment(DEPLOYMENT_ID, question="hi").answer == "ready"
253
+ assert seen == ["POST", "POST"]
254
+
255
+
256
+ def test_a_refused_connection_is_not_retried_past_the_budget(monkeypatch: pytest.MonkeyPatch):
257
+ seen: list[httpx.Request] = []
258
+ now = _clock(monkeypatch)
259
+
260
+ def answer(req: httpx.Request) -> httpx.Response:
261
+ seen.append(req)
262
+ now[0] += 1.0
263
+ raise httpx.ConnectError("[Errno 61] Connection refused", request=req)
264
+
265
+ _transport(monkeypatch, answer)
266
+ with pytest.raises(deployment_runs.RunNotSubmitted, match="in 1 attempt"):
267
+ _client().run_deployment(DEPLOYMENT_ID, timeout=1.2, question="hi")
268
+ assert len(seen) == 1
269
+
270
+
271
+ @pytest.mark.parametrize(
272
+ "failure",
273
+ [httpx.ReadTimeout, httpx.ReadError, httpx.WriteError, httpx.WriteTimeout, httpx.RemoteProtocolError],
274
+ )
275
+ def test_a_failure_after_the_connection_opened_stays_uncertain(
276
+ monkeypatch: pytest.MonkeyPatch, failure: type[httpx.TransportError]
277
+ ):
278
+ seen: list[httpx.Request] = []
279
+
280
+ def answer(req: httpx.Request) -> httpx.Response:
281
+ seen.append(req)
282
+ raise failure("lost", request=req)
283
+
284
+ _transport(monkeypatch, answer)
285
+ with pytest.raises(deployment_runs.RunSubmissionUncertain, match="uncertain") as caught:
286
+ _client().run_deployment(DEPLOYMENT_ID, question="hi")
287
+ assert not isinstance(caught.value, deployment_runs.RunNotSubmitted)
288
+ assert len(seen) == 1
289
+
290
+
202
291
  def test_wait_polls_after_accepted_response_without_resubmitting(monkeypatch: pytest.MonkeyPatch):
203
292
  seen: list[str] = []
204
293
  replies = [
@@ -272,6 +272,37 @@ def test_execute_stored_failure_preserves_run_id_and_provider_type(monkeypatch:
272
272
  assert type(caught.value) is httpx.HTTPStatusError
273
273
 
274
274
 
275
+ OUTAGE = (
276
+ "the provider at gw.lunaroute.com was unavailable: 3 attempt(s) over 3m1.367s; "
277
+ "its last answer was 503: backend unavailable"
278
+ )
279
+
280
+
281
+ def test_a_provider_outage_reads_as_the_providers_and_names_no_platform_status(monkeypatch: pytest.MonkeyPatch):
282
+ failure = {
283
+ "error": {"type": "ProviderUnavailable", "message": OUTAGE},
284
+ "execution_status": 500,
285
+ "retryable": True,
286
+ "retry_after": 120,
287
+ "failure": {"domain": "provider", "class": "provider_unavailable", "upstream_status": 503, "attempts": 3},
288
+ }
289
+ _transport(monkeypatch, lambda req: httpx.Response(200, json=_run("failed", failure), request=req))
290
+ with pytest.raises(execution.RetryableProviderError) as caught:
291
+ _client().run_deployment("d_ready")
292
+ assert str(caught.value) == f"Deployment run {RUN_ID} failed: {OUTAGE}"
293
+ # The status stays on the exception for a caller that reads it.
294
+ assert caught.value.response.status_code == 500
295
+ assert (caught.value.provider_status, caught.value.attempts, caught.value.retry_after) == (503, 3, 120)
296
+
297
+
298
+ def test_a_failure_that_is_not_the_providers_keeps_its_status(monkeypatch: pytest.MonkeyPatch):
299
+ failure = {"error": {"type": "RunFailed", "message": "KeyError: 'answer'"}, "execution_status": 500}
300
+ _transport(monkeypatch, lambda req: httpx.Response(200, json=_run("failed", failure), request=req))
301
+ with pytest.raises(httpx.HTTPStatusError) as caught:
302
+ _client().run_deployment("d_ready")
303
+ assert str(caught.value) == f"Deployment run {RUN_ID} failed with 500: KeyError: 'answer'"
304
+
305
+
275
306
  class TestDeployedProgram:
276
307
  def test_identity_and_repr(self):
277
308
  deployed = execution.DeployedProgram("d_ready")
@@ -505,7 +505,7 @@ wheels = [
505
505
 
506
506
  [[package]]
507
507
  name = "cmpnd"
508
- version = "0.80.0"
508
+ version = "0.81.0"
509
509
  source = { editable = "." }
510
510
  default-groups = ["dspy-3-4-1"]
511
511
  dependencies = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes