cmpnd 0.51.0__tar.gz → 0.52.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 (381) hide show
  1. {cmpnd-0.51.0 → cmpnd-0.52.0}/PKG-INFO +25 -34
  2. {cmpnd-0.51.0 → cmpnd-0.52.0}/README.md +24 -33
  3. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/callback.py +9 -0
  4. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/__init__.py +1 -2
  5. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/programs.py +17 -9
  6. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/top.py +33 -8
  7. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/shell.py +8 -9
  8. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/client.py +63 -40
  9. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/configuration.py +31 -4
  10. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/deployment.py +38 -19
  11. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/identity.py +23 -4
  12. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/named_programs.py +25 -1
  13. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimization.py +30 -13
  14. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/programs.py +21 -10
  15. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/cli.md +3 -16
  16. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/client.md +27 -15
  17. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/sdk-instrumentation.md +29 -18
  18. {cmpnd-0.51.0 → cmpnd-0.52.0}/pyproject.toml +1 -1
  19. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_client.py +43 -22
  20. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_client_program_names.py +97 -27
  21. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deploy.py +3 -0
  22. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deploy_mcp_tool_references.py +3 -0
  23. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deploy_program_id.py +10 -4
  24. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_execute_run_identity.py +3 -0
  25. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize.py +6 -1
  26. cmpnd-0.52.0/tests/test_program_id_deprecation.py +306 -0
  27. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_program_identity.py +4 -1
  28. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_program_names_in_deploy.py +16 -0
  29. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_programs_create.py +5 -1
  30. {cmpnd-0.51.0 → cmpnd-0.52.0}/uv.lock +1 -1
  31. {cmpnd-0.51.0 → cmpnd-0.52.0}/.gitignore +0 -0
  32. {cmpnd-0.51.0 → cmpnd-0.52.0}/AGENTS.md +0 -0
  33. {cmpnd-0.51.0 → cmpnd-0.52.0}/CLAUDE.md +0 -0
  34. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/__init__.py +0 -0
  35. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_assessments.py +0 -0
  36. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_authored_import.py +0 -0
  37. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_deployments.py +0 -0
  38. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_exporter_pool.py +0 -0
  39. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_gepa_patch.py +0 -0
  40. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_http.py +0 -0
  41. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_program_patch.py +0 -0
  42. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_rlm_patch.py +0 -0
  43. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_runtime_tools.py +0 -0
  44. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_timespec.py +0 -0
  45. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_traces.py +0 -0
  46. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/_valsets.py +0 -0
  47. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/authored.py +0 -0
  48. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/api_client.py +0 -0
  49. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/__init__.py +0 -0
  50. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/admin.py +0 -0
  51. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/assessments.py +0 -0
  52. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/auth.py +0 -0
  53. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/datasets.py +0 -0
  54. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/deployments.py +0 -0
  55. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/evals.py +0 -0
  56. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/login.py +0 -0
  57. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/optimizations.py +0 -0
  58. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/org.py +0 -0
  59. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  60. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/signatures.py +0 -0
  61. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  62. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/traces.py +0 -0
  63. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/commands/valsets.py +0 -0
  64. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/credentials.py +0 -0
  65. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/deprecation.py +0 -0
  66. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/pagination.py +0 -0
  67. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/trace_render.py +0 -0
  68. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/tree_help.py +0 -0
  69. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/cli/verbs.py +0 -0
  70. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/context.py +0 -0
  71. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/dataset_sync.py +0 -0
  72. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/datasets.py +0 -0
  73. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/decorators.py +0 -0
  74. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/deployment_metadata.py +0 -0
  75. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/deployment_runs.py +0 -0
  76. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/eval_handler.py +0 -0
  77. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/execution.py +0 -0
  78. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/exporter.py +0 -0
  79. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/exporter_http.py +0 -0
  80. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/helpers.py +0 -0
  81. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/imaging.py +0 -0
  82. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/__init__.py +0 -0
  83. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/decode.py +0 -0
  84. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/encode.py +0 -0
  85. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/hash.py +0 -0
  86. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/program.py +0 -0
  87. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/reflection.py +0 -0
  88. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/types.py +0 -0
  89. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/ir/xxh64.py +0 -0
  90. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/lm_configuration.py +0 -0
  91. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/mcp_servers.py +0 -0
  92. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/models.py +0 -0
  93. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimizers/__init__.py +0 -0
  94. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimizers/gepa.py +0 -0
  95. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  96. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimizers/resume.py +0 -0
  97. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/optimizers/tracker.py +0 -0
  98. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/packaging.py +0 -0
  99. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/references.py +0 -0
  100. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/retry.py +0 -0
  101. {cmpnd-0.51.0 → cmpnd-0.52.0}/cmpnd/traces.py +0 -0
  102. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/2026-04-02-code-review.md +0 -0
  103. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/custom-proposer.md +0 -0
  104. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  105. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  106. {cmpnd-0.51.0 → cmpnd-0.52.0}/docs/reading-traces.md +0 -0
  107. {cmpnd-0.51.0 → cmpnd-0.52.0}/examples/generalizing_proposer.py +0 -0
  108. {cmpnd-0.51.0 → cmpnd-0.52.0}/examples/local_ollama.py +0 -0
  109. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/LINEAGE.md +0 -0
  110. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/README.md +0 -0
  111. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  112. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  113. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  114. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  115. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  116. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  117. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/py.typed +0 -0
  118. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  119. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/retry.py +0 -0
  120. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  121. {cmpnd-0.51.0 → cmpnd-0.52.0}/ingest/pyproject.toml +0 -0
  122. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/audit-sdist.sh +0 -0
  123. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/capture_review_run.py +0 -0
  124. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/check-pip-install.sh +0 -0
  125. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/check_release_artifacts.py +0 -0
  126. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/fixtures/review_run.json.gz +0 -0
  127. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/gepa_resume_bug.py +0 -0
  128. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/release-stress.sh +0 -0
  129. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/require_version_bump.py +0 -0
  130. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/seed_review_run.py +0 -0
  131. {cmpnd-0.51.0 → cmpnd-0.52.0}/scripts/test-in-linux.sh +0 -0
  132. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/__init__.pyi +0 -0
  133. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  134. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  135. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/utils/__init__.pyi +0 -0
  136. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/utils/callback.pyi +0 -0
  137. {cmpnd-0.51.0 → cmpnd-0.52.0}/stubs/dspy/utils/dummies.pyi +0 -0
  138. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/__init__.py +0 -0
  139. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_deployment_signature_helpers.py +0 -0
  140. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_exporter_helpers.py +0 -0
  141. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_fake_clock.py +0 -0
  142. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_identity_helpers.py +0 -0
  143. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_resolve_refs.py +0 -0
  144. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/_traced_run.py +0 -0
  145. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/conftest.py +0 -0
  146. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/__init__.py +0 -0
  147. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/committee_task.py +0 -0
  148. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/conftest.py +0 -0
  149. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  150. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  151. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/fake_lm.py +0 -0
  152. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/helpers.py +0 -0
  153. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/target_capabilities.py +0 -0
  154. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_assessments_cli.py +0 -0
  155. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_capture_prompts.py +0 -0
  156. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_composite_module.py +0 -0
  157. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  158. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_execute.py +0 -0
  159. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_pandas.py +0 -0
  160. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_programs.py +0 -0
  161. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_edge_cases.py +0 -0
  162. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_example_hash.py +0 -0
  163. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_gepa_optimization.py +0 -0
  164. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_interpreter_spans.py +0 -0
  165. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_lm_accuracy.py +0 -0
  166. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_module_tracing.py +0 -0
  167. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimization_lineage.py +0 -0
  168. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  169. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_failures.py +0 -0
  170. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_loop.py +0 -0
  171. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  172. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  173. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_parallel_export.py +0 -0
  174. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_project_attribution.py +0 -0
  175. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_react_tool_spans.py +0 -0
  176. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_save_load.py +0 -0
  177. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_trace_structure.py +0 -0
  178. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_traces_read.py +0 -0
  179. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_user_attribution.py +0 -0
  180. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/e2e/test_valsets_cli.py +0 -0
  181. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  182. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  183. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  184. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  185. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  186. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  187. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  188. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  189. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  190. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/10_react.json +0 -0
  191. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/11_refine.json +0 -0
  192. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/12_retrieve.json +0 -0
  193. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/13_knn.json +0 -0
  194. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/14_parallel.json +0 -0
  195. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/identity_vectors/README.md +0 -0
  196. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/ingest_conformance.py +0 -0
  197. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/__init__.py +0 -0
  198. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/authored_optimize/judge.py +0 -0
  199. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  200. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/conftest.py +0 -0
  201. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  202. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/hosted_optimize_probe.py +0 -0
  203. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/optimization_run_probe.py +0 -0
  204. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  205. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/test_logs_renders_traces.py +0 -0
  206. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/test_optimization_run.py +0 -0
  207. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/test_optimizing_progress.py +0 -0
  208. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/integration/test_unhappy_path.py +0 -0
  209. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/__init__.py +0 -0
  210. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/__main__.py +0 -0
  211. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/drain.py +0 -0
  212. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/ingest.py +0 -0
  213. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/latency_transport.py +0 -0
  214. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/rlm_shape.py +0 -0
  215. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/rlm_size_report.py +0 -0
  216. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/sweep.py +0 -0
  217. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/test_rlm_shape.py +0 -0
  218. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/load/test_rlm_size_report.py +0 -0
  219. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/__init__.py +0 -0
  220. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/conftest.py +0 -0
  221. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/seed_parity.py +0 -0
  222. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_auth.py +0 -0
  223. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_datasets.py +0 -0
  224. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_deployments.py +0 -0
  225. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_evals.py +0 -0
  226. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_health.py +0 -0
  227. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_modules.py +0 -0
  228. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_optimizations.py +0 -0
  229. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_programs.py +0 -0
  230. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_signatures.py +0 -0
  231. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_trace_streaming.py +0 -0
  232. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/parity/test_traces.py +0 -0
  233. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/span_reference_fixture.py +0 -0
  234. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/__init__.py +0 -0
  235. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/_provider.py +0 -0
  236. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/_readiness.py +0 -0
  237. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/_reliability.py +0 -0
  238. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/_result.py +0 -0
  239. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/mint_bedrock_token.py +0 -0
  240. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_deploy_programs.py +0 -0
  241. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_multi_client_stress.py +0 -0
  242. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_optimize_client_committee.py +0 -0
  243. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_optimize_loop.py +0 -0
  244. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_optimize_loop_wasm.py +0 -0
  245. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_optimize_stress.py +0 -0
  246. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_provider_roles.py +0 -0
  247. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_readiness.py +0 -0
  248. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_real_provider_twins.py +0 -0
  249. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_reliability.py +0 -0
  250. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_reliability_classify.py +0 -0
  251. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_rlm_wasm.py +0 -0
  252. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/stress/test_trace_search.py +0 -0
  253. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_adapter_reentrancy.py +0 -0
  254. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_assessments_api.py +0 -0
  255. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_authored.py +0 -0
  256. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_authored_bundle_collisions.py +0 -0
  257. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_authored_metric_contract.py +0 -0
  258. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_authored_named_models.py +0 -0
  259. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_authored_optimize.py +0 -0
  260. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_callback.py +0 -0
  261. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_candidate_lineage.py +0 -0
  262. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/__init__.py +0 -0
  263. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/conftest.py +0 -0
  264. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_admin.py +0 -0
  265. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_api_client.py +0 -0
  266. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_assessments.py +0 -0
  267. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_auth.py +0 -0
  268. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_credentials.py +0 -0
  269. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_datasets.py +0 -0
  270. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_deployment_runs.py +0 -0
  271. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_deployments.py +0 -0
  272. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_evals.py +0 -0
  273. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_login.py +0 -0
  274. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_main.py +0 -0
  275. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_optimizations.py +0 -0
  276. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_org.py +0 -0
  277. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_pagination.py +0 -0
  278. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_parity.py +0 -0
  279. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_programs.py +0 -0
  280. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_provider_credentials.py +0 -0
  281. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_schema_sample.py +0 -0
  282. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_shell.py +0 -0
  283. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_signatures.py +0 -0
  284. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_tool_servers.py +0 -0
  285. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_top.py +0 -0
  286. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_traces.py +0 -0
  287. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  288. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_tree_help.py +0 -0
  289. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cli/test_valsets.py +0 -0
  290. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_client_floor.py +0 -0
  291. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_clustering/__init__.py +0 -0
  292. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_clustering/conftest.py +0 -0
  293. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_clustering/test_edge_cases.py +0 -0
  294. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  295. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_clustering/test_type_conversion.py +0 -0
  296. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_cmp551_grouping_identity.py +0 -0
  297. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_configuration.py +0 -0
  298. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_context.py +0 -0
  299. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_context_propagation.py +0 -0
  300. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_dataset_polling.py +0 -0
  301. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_dataset_sync.py +0 -0
  302. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_datasets.py +0 -0
  303. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_decision_client_spans.py +0 -0
  304. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_decorators.py +0 -0
  305. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deployment_metadata.py +0 -0
  306. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deployment_runs.py +0 -0
  307. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_deployments_read.py +0 -0
  308. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_eval.py +0 -0
  309. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_eval_example_attribution.py +0 -0
  310. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_eval_start.py +0 -0
  311. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_eval_trace_grouping.py +0 -0
  312. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_exception_paths.py +0 -0
  313. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_execute.py +0 -0
  314. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_exporter.py +0 -0
  315. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_exporter_program_names.py +0 -0
  316. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_exporter_queue.py +0 -0
  317. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_exporter_real.py +0 -0
  318. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_fake_lm.py +0 -0
  319. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_gepa_callback.py +0 -0
  320. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_gepa_integration.py +0 -0
  321. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_gepa_output_normalization.py +0 -0
  322. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_gepa_resume.py +0 -0
  323. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_identity.py +0 -0
  324. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_imaging.py +0 -0
  325. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_import_weight.py +0 -0
  326. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_ingest_conformance.py +0 -0
  327. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_ingest_second_producer.py +0 -0
  328. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_integration.py +0 -0
  329. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_interpreter_callback.py +0 -0
  330. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_ir_encoder_properties.py +0 -0
  331. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_ir_golden_vectors.py +0 -0
  332. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_ir_roundtrip.py +0 -0
  333. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_lm15_native_calls.py +0 -0
  334. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_lm_configuration.py +0 -0
  335. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_lm_usage_shapes.py +0 -0
  336. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_mcp_tools.py +0 -0
  337. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_models.py +0 -0
  338. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_multi_client_stress_readiness.py +0 -0
  339. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimization_progress.py +0 -0
  340. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimization_start.py +0 -0
  341. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_budget.py +0 -0
  342. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_lift.py +0 -0
  343. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_lms.py +0 -0
  344. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_proposer.py +0 -0
  345. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_reflection_lm.py +0 -0
  346. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_optimize_terminal_failure.py +0 -0
  347. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_packaging.py +0 -0
  348. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_packaging_callable_source.py +0 -0
  349. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_packaging_mcp_tools.py +0 -0
  350. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_packaging_program_source.py +0 -0
  351. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_poll_until.py +0 -0
  352. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_program_lineage_persist.py +0 -0
  353. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_project_payload.py +0 -0
  354. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_real_provider_twins_readiness.py +0 -0
  355. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_reflector_properties.py +0 -0
  356. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_reflector_smoke.py +0 -0
  357. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_release_stress_script.py +0 -0
  358. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_repro_reactv2_bugs.py +0 -0
  359. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_require_version_bump.py +0 -0
  360. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_retry.py +0 -0
  361. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_reversible_failures.py +0 -0
  362. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_rlm_patch.py +0 -0
  363. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_run_attribution_paths.py +0 -0
  364. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_runtime_tools.py +0 -0
  365. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_schemas.py +0 -0
  366. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_seed_review_run.py +0 -0
  367. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_signature_inputs.py +0 -0
  368. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_span_references.py +0 -0
  369. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_span_sent_once.py +0 -0
  370. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_system_one.py +0 -0
  371. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_trace_context_concurrency.py +0 -0
  372. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_trace_fact_wire_contract.py +0 -0
  373. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_trace_facts.py +0 -0
  374. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_trace_render.py +0 -0
  375. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_traces_read.py +0 -0
  376. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_tracked_gepa.py +0 -0
  377. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_tracker_enrich.py +0 -0
  378. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_truncation.py +0 -0
  379. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_upload_auth_headers.py +0 -0
  380. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_valsets_api.py +0 -0
  381. {cmpnd-0.51.0 → cmpnd-0.52.0}/tests/test_xxh64.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.51.0
3
+ Version: 0.52.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>
@@ -88,7 +88,6 @@ no arguments. The endpoint defaults to `https://platform.cmpnd.ai`.
88
88
  ```bash
89
89
  export CMPND_API_KEY="ck_your_api_key"
90
90
  export CMPND_ENDPOINT="https://platform.cmpnd.ai" # optional
91
- export CMPND_PROGRAM_ID="p_0123456789Ab" # optional: the program these traces belong to
92
91
  ```
93
92
 
94
93
  ```python
@@ -96,7 +95,6 @@ cmpnd.configure(
96
95
  api_key="ck_xxx", # required, or CMPND_API_KEY
97
96
  endpoint="https://platform.cmpnd.ai", # optional, or CMPND_ENDPOINT
98
97
  project_tags="my-project", # optional: one tag or a list of tags
99
- program_id="p_0123456789Ab", # optional, or CMPND_PROGRAM_ID: the id `cmpnd programs create` prints
100
98
  batch_size=100, # optional: spans per export batch
101
99
  flush_interval_seconds=5.0, # optional: seconds between flushes
102
100
  capture_inputs=True, # optional: record span inputs
@@ -111,24 +109,18 @@ captured input and output size limits, 65,536 bytes each by default.
111
109
 
112
110
  ## Deployment
113
111
 
114
- Every deployment belongs to a program, and the platform issues each program
115
- an id. Create a program first. The command prints its id:
116
-
117
- ```bash
118
- cmpnd programs create --name qa
119
- ```
120
-
121
- Then deploy a DSPy module under that program for server-side execution:
112
+ Every deployment belongs to a program, and each program has a program name.
113
+ Give a DSPy module a program name with `cmpnd.Program`, then deploy it for
114
+ server-side execution:
122
115
 
123
116
  ```python
124
117
  import cmpnd
125
118
  import dspy
126
119
 
127
- cmpnd.configure(api_key="ck_xxx", program_id="p_0123456789Ab")
128
- dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
120
+ cmpnd.configure(api_key="ck_xxx")
129
121
 
130
- module = dspy.Predict("question -> answer")
131
- deployed = cmpnd.deploy(module)
122
+ qa = cmpnd.Program("qa", module=dspy.Predict("question -> answer"), lm=dspy.LM("openai/gpt-6-luna"))
123
+ deployed = cmpnd.deploy(qa)
132
124
 
133
125
  result = deployed(question="What is DSPy?") # runs server-side
134
126
  print(result.answer)
@@ -143,26 +135,26 @@ when the platform has inspected it. An unknown interface leaves `input_fields`
143
135
  and `output_fields` as `None`. A known interface with no fields returns empty
144
136
  lists.
145
137
 
146
- `cmpnd.deploy(module, program_id="p_…")` names the program for one call.
147
- Without a configured or passed id, `deploy` raises `ValueError` before it
148
- packages or sends anything.
138
+ The platform makes the program the first time your organization uses the
139
+ program name. Later deploys under the same program name go to the same
140
+ program. `@cmpnd.program("qa")` above a `dspy.Module`
141
+ class declares the same program name. [`docs/client.md`](docs/client.md)
142
+ describes both forms.
149
143
 
150
- To deploy a source file, run `cmpnd deploy program.py --program-id p_…`, or
151
- set `CMPND_PROGRAM_ID`. The CLI uploads the file's exact bytes and does not
152
- reconstruct the source from a live object. Use `--source-root` and repeated
153
- `--include` flags for sibling modules or data, and `cmpnd inspect <id>
154
- --source` to read the deployed entry file back. [`docs/cli.md`](docs/cli.md)
155
- covers the CLI.
144
+ To deploy a source file, run `cmpnd deploy program.py qa`. The CLI uploads
145
+ the file's exact bytes and does not reconstruct the source from a live object.
146
+ Use `--source-root` and repeated `--include` flags for sibling modules or
147
+ data, and `cmpnd inspect <id> --source` to read the deployed entry file back.
148
+ [`docs/cli.md`](docs/cli.md) covers the CLI.
156
149
 
157
150
  ### Options
158
151
 
159
152
  ```python
160
153
  cmpnd.deploy(
161
- module, # required: a DSPy module
154
+ program, # required: a cmpnd.Program
162
155
  metric=None, # optional: a metric callable, packaged for optimization
163
156
  timeout=300, # optional: seconds to wait for the parser after the upload
164
157
  metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
165
- program_id="p_…", # the program the deployment belongs to; serve requires it after self-host 2026-001
166
158
  )
167
159
  ```
168
160
 
@@ -190,10 +182,9 @@ it returns a `DeployedProgram` that you call directly, and the program's
190
182
  import cmpnd
191
183
  import dspy
192
184
 
193
- cmpnd.configure(api_key="ck_xxx", program_id="p_0123456789Ab") # from `cmpnd programs create`
194
- dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
185
+ cmpnd.configure(api_key="ck_xxx")
195
186
 
196
- program = dspy.ChainOfThought("topic -> haiku")
187
+ program = cmpnd.Program("haiku", module=dspy.ChainOfThought("topic -> haiku"), lm=dspy.LM("openai/gpt-6-luna"))
197
188
 
198
189
  # GEPA needs a five-argument feedback metric that returns dspy.Prediction(score=, feedback=)
199
190
  def metric(example, pred, trace=None, pred_name=None, pred_trace=None):
@@ -327,13 +318,13 @@ raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
327
318
  ### From the CLI
328
319
 
329
320
  ```bash
330
- cmpnd optimize gepa task.py --program-id p_0123456789Ab --reflection-model openai/gpt-6-luna --auto light
321
+ cmpnd optimize gepa task.py haiku --reflection-model openai/gpt-6-luna --auto light
331
322
  ```
332
323
 
333
324
  The file, or `-` for stdin, binds `program`, `trainset`, `valset` and
334
325
  `metric`. The CLI prints the best deployment ID. The CLI deploys the file's
335
- program first, so it needs `--program-id` or `CMPND_PROGRAM_ID`. With
336
- `--deployment-id`, the program id is optional.
326
+ program first under the program name, here `haiku`. With `--deployment-id`,
327
+ the CLI starts from that deployment and needs no program name.
337
328
 
338
329
  ## Custom spans
339
330
 
@@ -403,8 +394,8 @@ dspy.configure(callbacks=[cmpnd.CmpndCallback()])
403
394
 
404
395
  ### `cmpnd.deploy()`
405
396
 
406
- Deploys a DSPy module under a program id and returns a callable
407
- `DeployedProgram`. It uses `program_id=`, else the configured id.
397
+ Deploys a `cmpnd.Program` under its program name and returns a callable
398
+ `DeployedProgram`.
408
399
 
409
400
  ### `cmpnd.optimize()`
410
401
 
@@ -37,7 +37,6 @@ no arguments. The endpoint defaults to `https://platform.cmpnd.ai`.
37
37
  ```bash
38
38
  export CMPND_API_KEY="ck_your_api_key"
39
39
  export CMPND_ENDPOINT="https://platform.cmpnd.ai" # optional
40
- export CMPND_PROGRAM_ID="p_0123456789Ab" # optional: the program these traces belong to
41
40
  ```
42
41
 
43
42
  ```python
@@ -45,7 +44,6 @@ cmpnd.configure(
45
44
  api_key="ck_xxx", # required, or CMPND_API_KEY
46
45
  endpoint="https://platform.cmpnd.ai", # optional, or CMPND_ENDPOINT
47
46
  project_tags="my-project", # optional: one tag or a list of tags
48
- program_id="p_0123456789Ab", # optional, or CMPND_PROGRAM_ID: the id `cmpnd programs create` prints
49
47
  batch_size=100, # optional: spans per export batch
50
48
  flush_interval_seconds=5.0, # optional: seconds between flushes
51
49
  capture_inputs=True, # optional: record span inputs
@@ -60,24 +58,18 @@ captured input and output size limits, 65,536 bytes each by default.
60
58
 
61
59
  ## Deployment
62
60
 
63
- Every deployment belongs to a program, and the platform issues each program
64
- an id. Create a program first. The command prints its id:
65
-
66
- ```bash
67
- cmpnd programs create --name qa
68
- ```
69
-
70
- Then deploy a DSPy module under that program for server-side execution:
61
+ Every deployment belongs to a program, and each program has a program name.
62
+ Give a DSPy module a program name with `cmpnd.Program`, then deploy it for
63
+ server-side execution:
71
64
 
72
65
  ```python
73
66
  import cmpnd
74
67
  import dspy
75
68
 
76
- cmpnd.configure(api_key="ck_xxx", program_id="p_0123456789Ab")
77
- dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
69
+ cmpnd.configure(api_key="ck_xxx")
78
70
 
79
- module = dspy.Predict("question -> answer")
80
- deployed = cmpnd.deploy(module)
71
+ qa = cmpnd.Program("qa", module=dspy.Predict("question -> answer"), lm=dspy.LM("openai/gpt-6-luna"))
72
+ deployed = cmpnd.deploy(qa)
81
73
 
82
74
  result = deployed(question="What is DSPy?") # runs server-side
83
75
  print(result.answer)
@@ -92,26 +84,26 @@ when the platform has inspected it. An unknown interface leaves `input_fields`
92
84
  and `output_fields` as `None`. A known interface with no fields returns empty
93
85
  lists.
94
86
 
95
- `cmpnd.deploy(module, program_id="p_…")` names the program for one call.
96
- Without a configured or passed id, `deploy` raises `ValueError` before it
97
- packages or sends anything.
87
+ The platform makes the program the first time your organization uses the
88
+ program name. Later deploys under the same program name go to the same
89
+ program. `@cmpnd.program("qa")` above a `dspy.Module`
90
+ class declares the same program name. [`docs/client.md`](docs/client.md)
91
+ describes both forms.
98
92
 
99
- To deploy a source file, run `cmpnd deploy program.py --program-id p_…`, or
100
- set `CMPND_PROGRAM_ID`. The CLI uploads the file's exact bytes and does not
101
- reconstruct the source from a live object. Use `--source-root` and repeated
102
- `--include` flags for sibling modules or data, and `cmpnd inspect <id>
103
- --source` to read the deployed entry file back. [`docs/cli.md`](docs/cli.md)
104
- covers the CLI.
93
+ To deploy a source file, run `cmpnd deploy program.py qa`. The CLI uploads
94
+ the file's exact bytes and does not reconstruct the source from a live object.
95
+ Use `--source-root` and repeated `--include` flags for sibling modules or
96
+ data, and `cmpnd inspect <id> --source` to read the deployed entry file back.
97
+ [`docs/cli.md`](docs/cli.md) covers the CLI.
105
98
 
106
99
  ### Options
107
100
 
108
101
  ```python
109
102
  cmpnd.deploy(
110
- module, # required: a DSPy module
103
+ program, # required: a cmpnd.Program
111
104
  metric=None, # optional: a metric callable, packaged for optimization
112
105
  timeout=300, # optional: seconds to wait for the parser after the upload
113
106
  metadata=None, # optional: a JSON-serializable dict, at most 64 KiB, stored with the deployment
114
- program_id="p_…", # the program the deployment belongs to; serve requires it after self-host 2026-001
115
107
  )
116
108
  ```
117
109
 
@@ -139,10 +131,9 @@ it returns a `DeployedProgram` that you call directly, and the program's
139
131
  import cmpnd
140
132
  import dspy
141
133
 
142
- cmpnd.configure(api_key="ck_xxx", program_id="p_0123456789Ab") # from `cmpnd programs create`
143
- dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
134
+ cmpnd.configure(api_key="ck_xxx")
144
135
 
145
- program = dspy.ChainOfThought("topic -> haiku")
136
+ program = cmpnd.Program("haiku", module=dspy.ChainOfThought("topic -> haiku"), lm=dspy.LM("openai/gpt-6-luna"))
146
137
 
147
138
  # GEPA needs a five-argument feedback metric that returns dspy.Prediction(score=, feedback=)
148
139
  def metric(example, pred, trace=None, pred_name=None, pred_trace=None):
@@ -276,13 +267,13 @@ raises `cmpnd.OptimizeFailed` when a step reaches `failed`.
276
267
  ### From the CLI
277
268
 
278
269
  ```bash
279
- cmpnd optimize gepa task.py --program-id p_0123456789Ab --reflection-model openai/gpt-6-luna --auto light
270
+ cmpnd optimize gepa task.py haiku --reflection-model openai/gpt-6-luna --auto light
280
271
  ```
281
272
 
282
273
  The file, or `-` for stdin, binds `program`, `trainset`, `valset` and
283
274
  `metric`. The CLI prints the best deployment ID. The CLI deploys the file's
284
- program first, so it needs `--program-id` or `CMPND_PROGRAM_ID`. With
285
- `--deployment-id`, the program id is optional.
275
+ program first under the program name, here `haiku`. With `--deployment-id`,
276
+ the CLI starts from that deployment and needs no program name.
286
277
 
287
278
  ## Custom spans
288
279
 
@@ -352,8 +343,8 @@ dspy.configure(callbacks=[cmpnd.CmpndCallback()])
352
343
 
353
344
  ### `cmpnd.deploy()`
354
345
 
355
- Deploys a DSPy module under a program id and returns a callable
356
- `DeployedProgram`. It uses `program_id=`, else the configured id.
346
+ Deploys a `cmpnd.Program` under its program name and returns a callable
347
+ `DeployedProgram`.
357
348
 
358
349
  ### `cmpnd.optimize()`
359
350
 
@@ -651,6 +651,15 @@ class _CallbackBase:
651
651
  self._last_eval_trace_ids.clear()
652
652
  self._unclaimed_eval_trace_ids.clear()
653
653
 
654
+ @property
655
+ def traces_globally(self) -> bool:
656
+ """Whether this is the ``auto_instrument()`` callback, which reads the global config.
657
+
658
+ A client's callback has its own config. The global callback records sketch
659
+ mode, which declares no program names.
660
+ """
661
+ return self._own_config is None
662
+
654
663
  def _resolve_project_tags(self) -> list[str] | None:
655
664
  """The project tags this callback stamps on the builders it creates.
656
665
 
@@ -61,8 +61,7 @@ class _LazyVersionAction(argparse.Action):
61
61
  _EPILOG = """\
62
62
  deploy-flow workflow (Docker-style; the path an agent should reach for first):
63
63
 
64
- cmpnd programs create --name qa # mint a program id (p_…), once
65
- cmpnd deploy program.py --program-id p_… --run '{"question": "..."}' # deploy + smoke test
64
+ cmpnd deploy program.py qa --run '{"question": "..."}' # deploy program name qa + smoke test
66
65
  cmpnd ps # list deployments
67
66
  cmpnd status <id> -f # wait for terminal state
68
67
  cmpnd run <id> '{"...": "..."}' # invoke a ready deployment
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import argparse
5
6
  import sys
6
7
  from argparse import ArgumentParser, _SubParsersAction
7
8
  from typing import Any
@@ -23,21 +24,22 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
23
24
  "create",
24
25
  help="Create a program with a name",
25
26
  description=(
26
- "Create a program with PROGRAM_NAME in your organization and print its id on stdout. "
27
- "A program name that already has a program is refused. Deploy under the program name with "
28
- "`cmpnd deploy SOURCE PROGRAM_NAME`, and declare it in Python with "
29
- "cmpnd.Program(PROGRAM_NAME, module=..., lm=...). Without PROGRAM_NAME, --name creates an "
30
- "unnamed program with a display name, as earlier releases did."
27
+ "Create a program with PROGRAM_NAME in your organization. A program name that already "
28
+ "has a program is refused. A deploy makes the program the first time it uses the program "
29
+ "name, so this command is needed only to make the program first. Deploy under the program "
30
+ "name with `cmpnd deploy SOURCE PROGRAM_NAME`, and declare it in Python with "
31
+ "cmpnd.Program(PROGRAM_NAME, module=..., lm=...)."
31
32
  ),
32
33
  )
33
34
  create.add_argument(
34
35
  "name", nargs="?", default=None, metavar="PROGRAM_NAME", help="Program name, unique in your organization"
35
36
  )
37
+ # Deprecated program id input: --name, the display name of an unnamed program, goes when it is removed.
36
38
  create.add_argument(
37
39
  "--name",
38
40
  dest="display_name",
39
41
  default=None,
40
- help="Display name of an unnamed program (need not be unique)",
42
+ help=argparse.SUPPRESS,
41
43
  )
42
44
  create.add_argument("--json", action="store_true", help="Emit the created program as JSON instead of its id")
43
45
  create.set_defaults(func=handle_create)
@@ -96,13 +98,19 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
96
98
 
97
99
 
98
100
  def handle_create(client: api_client.ApiClient, args: Any) -> Any:
99
- """Create a program. Prints the bare id on stdout so a script can capture it
100
- (``PROGRAM_ID=$(cmpnd programs create triage)``) and says what it made on stderr;
101
- ``--json`` returns serve's whole answer instead, printed like the group's reads."""
101
+ """Create a program. Prints the bare id on stdout and says what it made on stderr;
102
+ ``--json`` returns serve's whole answer instead, printed like the group's reads.
103
+
104
+ The form without a program name, with or without ``--name``, makes an unnamed
105
+ program. It is deprecated, and warns."""
102
106
  from ... import programs
103
107
 
104
108
  if args.name is not None:
105
109
  return _create_named(client, args)
110
+ # Deprecated program id input: a create without a program name, and this warning, go when it is removed.
111
+ from . import top
112
+
113
+ top.warn_program_id_input("`cmpnd programs create` without a program name", top.hint_programs_create())
106
114
  row = programs.send_create(client, name=args.display_name)
107
115
  if getattr(args, "json", False):
108
116
  return row
@@ -7,6 +7,7 @@ client-side deployment-id prefix resolution.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ import argparse
10
11
  import json
11
12
  import os
12
13
  import sys
@@ -207,6 +208,11 @@ def _hint_program_name(verb: str, *, source: str | None = None, name: str = "cap
207
208
  return f"cmpnd deploy {source} {name}"
208
209
 
209
210
 
211
+ def hint_programs_create(name: str = "capital-qa") -> str:
212
+ """How to create a program with a program name. The shell has no programs verb, so this is the CLI form."""
213
+ return f"cmpnd programs create {name}"
214
+
215
+
210
216
  def _hint_status(deployment_id: str, follow: bool = False) -> str:
211
217
  short = _short_id(deployment_id)
212
218
  if _SHELL_MODE:
@@ -823,6 +829,17 @@ def _parse_deploy_metadata(raw: str | None) -> dict[str, Any] | None:
823
829
  raise api_client.CliError(f"--metadata is invalid: {exc}")
824
830
 
825
831
 
832
+ # Deprecated program id input: the CLI's warning for every one of them, which goes when they are removed.
833
+ def warn_program_id_input(source: str, example: str) -> None:
834
+ """Print that the program id input ``source`` is deprecated, and show the program name form.
835
+
836
+ The CLI prints its warnings on stderr. A ``FutureWarning`` here would name a file and
837
+ line inside the SDK, which tells a command-line user nothing.
838
+ """
839
+ print(f"warning: {source} is deprecated; give a program name instead, as in `{example}`.", file=sys.stderr)
840
+
841
+
842
+ # Deprecated program id input: --program-id and CMPND_PROGRAM_ID on a deploy or optimize.
826
843
  def _program_id_arg(value: str | None) -> str | None:
827
844
  """The program id a deploy or optimize names: ``--program-id``, else ``CMPND_PROGRAM_ID``.
828
845
 
@@ -858,10 +875,13 @@ def _program_name_arg(value: str | None) -> str | None:
858
875
  def _program_args(args: Any, verb: str, *, needs_name: bool = True) -> tuple[str | None, str | None]:
859
876
  """The program name and program id a deploy or optimize names, checked before a file is staged.
860
877
 
861
- The name follows the source file. ``--program-id`` is the older input: it still
862
- works, warns, and cannot be given with a name. A command with no name and no id
863
- from either input warns that it will need a name, unless ``needs_name`` is false
864
- because a deployment it reuses already names its program.
878
+ The name follows the source file. ``--program-id`` and ``CMPND_PROGRAM_ID`` are the
879
+ deprecated inputs: they still work and warn, and ``--program-id`` cannot be given
880
+ with a name. A name wins over ``CMPND_PROGRAM_ID``, and the deploy says the id is not
881
+ used. A command with no name and no id from either input warns that it will need a
882
+ name, unless ``needs_name`` is false because a deployment it reuses already names
883
+ its program. The CLI never runs inside a worker, so ``CMPND_PROGRAM_ID`` here is a
884
+ user's input, not a worker's.
865
885
  """
866
886
  name = _program_name_arg(getattr(args, "program_name", None))
867
887
  flag = getattr(args, "program_id", None)
@@ -869,8 +889,11 @@ def _program_args(args: Any, verb: str, *, needs_name: bool = True) -> tuple[str
869
889
  id_input = "program_id=" if _SHELL_MODE else "--program-id"
870
890
  if name is not None and flag is not None:
871
891
  raise api_client.CliError(f"give a program name or {id_input}, not both")
892
+ # Deprecated program id input: both warnings go when the id inputs are removed.
872
893
  if flag is not None:
873
- print(f"warning: {id_input} is deprecated; give a program name instead, as in `{example}`.", file=sys.stderr)
894
+ warn_program_id_input(id_input, example)
895
+ elif name is None and os.environ.get("CMPND_PROGRAM_ID"):
896
+ warn_program_id_input("CMPND_PROGRAM_ID", example)
874
897
  program_id = _program_id_arg(flag)
875
898
  if name is None and program_id is None and needs_name:
876
899
  print(f"warning: this command has no program name; give one, as in `{example}`.", file=sys.stderr)
@@ -897,7 +920,7 @@ def cmd_deploy(client: api_client.ApiClient, args: Any) -> None:
897
920
  from ... import authored, configuration, deployment
898
921
 
899
922
  program_name, program_id = _program_args(args, "deploy")
900
- configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=program_id)
923
+ configuration._configure(client._api_key, client._endpoint, None, program_id)
901
924
  try:
902
925
  if args.source == "-" or args.source is None:
903
926
  prepared = authored.prepare_stdin(
@@ -991,7 +1014,7 @@ def cmd_optimize(client: api_client.ApiClient, args: Any) -> Any:
991
1014
 
992
1015
  deployment_id = getattr(args, "deployment_id", None)
993
1016
  program_name, program_id = _program_args(args, "optimize", needs_name=deployment_id is None)
994
- configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=program_id)
1017
+ configuration._configure(client._api_key, client._endpoint, None, program_id)
995
1018
  try:
996
1019
  if args.source == "-" or args.source is None:
997
1020
  prepared = authored.prepare_optimize_stdin(
@@ -1149,11 +1172,13 @@ def _add_program_options(parser: ArgumentParser, role: str) -> None:
1149
1172
  help=f"Program name {role}. The platform makes the program the first time "
1150
1173
  "your organization uses the program name",
1151
1174
  )
1175
+ # Deprecated program id input: --program-id goes when it is removed.
1152
1176
  parser.add_argument(
1153
1177
  "--program-id",
1154
1178
  dest="program_id",
1155
1179
  default=None,
1156
- help="Deprecated; give a program name instead. Program id (p_…), defaults to CMPND_PROGRAM_ID",
1180
+ # Hidden so that help shows program names only.
1181
+ help=argparse.SUPPRESS,
1157
1182
  )
1158
1183
  # argparse leaves a name given after other options unplaced; cli.parse places it.
1159
1184
  parser.set_defaults(_late_positional="program_name")
@@ -485,15 +485,14 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
485
485
  entrypoint: str = "program",
486
486
  source_root: str | None = None,
487
487
  include: list[str] | None = None,
488
- program_id: str | None = None,
488
+ program_id: str | None = None, # Deprecated program id input: goes when it is removed.
489
489
  program: str | None = None,
490
490
  ) -> Deployment:
491
491
  """Deploy authored Python from a file or ``"-"`` for stdin.
492
492
 
493
- ``program`` names the program the deployment belongs to, which the platform
494
- makes the first time your organization uses the name. ``program_id``
495
- (``p_…``) is the older way to name it, and defaults to ``CMPND_PROGRAM_ID``.
496
- A name wins over an id. A fresh child imports the staged bundle. The shell
493
+ ``program`` is the program name of the deployment. The platform makes the
494
+ program the first time your organization uses the program name. A fresh
495
+ child imports the staged bundle. The shell
497
496
  does not execute the file in its own process. Returns the
498
497
  new Deployment entity so you can chain ``.watch()`` / ``.run({...})``
499
498
  directly; also invalidates ``deps`` so the new deployment shows up
@@ -504,7 +503,7 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
504
503
  program_name, declared = commands.top._program_args(
505
504
  _args(program_name=program, program_id=program_id), "deploy"
506
505
  )
507
- configuration.configure(api_key=client._api_key, endpoint=client._endpoint, program_id=declared)
506
+ configuration._configure(client._api_key, client._endpoint, None, declared)
508
507
  if source in ("-", None):
509
508
  prepared = authored.prepare_stdin(
510
509
  sys.stdin.buffer.read(),
@@ -541,7 +540,7 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
541
540
  max_steps: int = 10,
542
541
  patience: int = 2,
543
542
  seed: int = 0,
544
- program_id: str | None = None,
543
+ program_id: str | None = None, # Deprecated program id input: goes when it is removed.
545
544
  program: str | None = None,
546
545
  ) -> Any:
547
546
  """Optimize a DSPy program: ``optimize("gepa", "task.py")``.
@@ -553,8 +552,8 @@ def _make_namespace(client: api_client.ApiClient, endpoint: str) -> dict[str, An
553
552
  than executed here, so what scores the run is the file's own bytes. ``include``
554
553
  adds the siblings it imports and the files it reads. Returns the best
555
554
  ``DeployedProgram`` (call it directly; ``.score`` is the best score found);
556
- ``deps`` is refreshed so the result deployment shows up. The ``program``
557
- argument names the program being optimized, as ``deploy`` takes it.
555
+ ``deps`` is refreshed so the result deployment shows up. ``program`` is the
556
+ program name of the program being optimized, as ``deploy`` takes it.
558
557
  """
559
558
  result = commands.top.cmd_optimize(
560
559
  client,