cmpnd 0.50.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.50.0 → cmpnd-0.52.0}/PKG-INFO +25 -34
  2. {cmpnd-0.50.0 → cmpnd-0.52.0}/README.md +24 -33
  3. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/callback.py +9 -0
  4. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/__init__.py +20 -3
  5. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/programs.py +59 -10
  6. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/top.py +111 -30
  7. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/shell.py +17 -9
  8. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/client.py +63 -40
  9. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/configuration.py +31 -4
  10. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/deployment.py +132 -17
  11. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/identity.py +23 -4
  12. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/named_programs.py +25 -1
  13. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimization.py +42 -16
  14. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/packaging.py +12 -6
  15. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/programs.py +46 -10
  16. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/cli.md +34 -28
  17. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/client.md +39 -20
  18. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/sdk-instrumentation.md +29 -18
  19. {cmpnd-0.50.0 → cmpnd-0.52.0}/pyproject.toml +1 -1
  20. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_authored_metric_contract.py +1 -1
  21. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_authored_optimize.py +4 -2
  22. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_top.py +4 -4
  23. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_client.py +43 -22
  24. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_client_program_names.py +99 -29
  25. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deploy.py +3 -0
  26. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deploy_mcp_tool_references.py +3 -0
  27. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deploy_program_id.py +14 -8
  28. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_execute_run_identity.py +3 -0
  29. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize.py +6 -1
  30. cmpnd-0.52.0/tests/test_program_id_deprecation.py +306 -0
  31. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_program_identity.py +4 -1
  32. cmpnd-0.52.0/tests/test_program_names_in_deploy.py +643 -0
  33. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_programs_create.py +5 -1
  34. {cmpnd-0.50.0 → cmpnd-0.52.0}/uv.lock +1 -1
  35. {cmpnd-0.50.0 → cmpnd-0.52.0}/.gitignore +0 -0
  36. {cmpnd-0.50.0 → cmpnd-0.52.0}/AGENTS.md +0 -0
  37. {cmpnd-0.50.0 → cmpnd-0.52.0}/CLAUDE.md +0 -0
  38. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/__init__.py +0 -0
  39. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_assessments.py +0 -0
  40. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_authored_import.py +0 -0
  41. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_deployments.py +0 -0
  42. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_exporter_pool.py +0 -0
  43. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_gepa_patch.py +0 -0
  44. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_http.py +0 -0
  45. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_program_patch.py +0 -0
  46. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_rlm_patch.py +0 -0
  47. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_runtime_tools.py +0 -0
  48. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_timespec.py +0 -0
  49. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_traces.py +0 -0
  50. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/_valsets.py +0 -0
  51. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/authored.py +0 -0
  52. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/api_client.py +0 -0
  53. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/__init__.py +0 -0
  54. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/admin.py +0 -0
  55. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/assessments.py +0 -0
  56. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/auth.py +0 -0
  57. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/datasets.py +0 -0
  58. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/deployments.py +0 -0
  59. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/evals.py +0 -0
  60. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/login.py +0 -0
  61. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/optimizations.py +0 -0
  62. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/org.py +0 -0
  63. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  64. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/signatures.py +0 -0
  65. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  66. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/traces.py +0 -0
  67. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/commands/valsets.py +0 -0
  68. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/credentials.py +0 -0
  69. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/deprecation.py +0 -0
  70. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/pagination.py +0 -0
  71. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/trace_render.py +0 -0
  72. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/tree_help.py +0 -0
  73. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/cli/verbs.py +0 -0
  74. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/context.py +0 -0
  75. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/dataset_sync.py +0 -0
  76. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/datasets.py +0 -0
  77. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/decorators.py +0 -0
  78. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/deployment_metadata.py +0 -0
  79. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/deployment_runs.py +0 -0
  80. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/eval_handler.py +0 -0
  81. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/execution.py +0 -0
  82. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/exporter.py +0 -0
  83. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/exporter_http.py +0 -0
  84. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/helpers.py +0 -0
  85. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/imaging.py +0 -0
  86. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/__init__.py +0 -0
  87. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/decode.py +0 -0
  88. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/encode.py +0 -0
  89. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/hash.py +0 -0
  90. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/program.py +0 -0
  91. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/reflection.py +0 -0
  92. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/types.py +0 -0
  93. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/ir/xxh64.py +0 -0
  94. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/lm_configuration.py +0 -0
  95. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/mcp_servers.py +0 -0
  96. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/models.py +0 -0
  97. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimizers/__init__.py +0 -0
  98. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimizers/gepa.py +0 -0
  99. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  100. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimizers/resume.py +0 -0
  101. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/optimizers/tracker.py +0 -0
  102. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/references.py +0 -0
  103. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/retry.py +0 -0
  104. {cmpnd-0.50.0 → cmpnd-0.52.0}/cmpnd/traces.py +0 -0
  105. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/2026-04-02-code-review.md +0 -0
  106. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/custom-proposer.md +0 -0
  107. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  108. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  109. {cmpnd-0.50.0 → cmpnd-0.52.0}/docs/reading-traces.md +0 -0
  110. {cmpnd-0.50.0 → cmpnd-0.52.0}/examples/generalizing_proposer.py +0 -0
  111. {cmpnd-0.50.0 → cmpnd-0.52.0}/examples/local_ollama.py +0 -0
  112. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/LINEAGE.md +0 -0
  113. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/README.md +0 -0
  114. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  115. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  116. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  117. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  118. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  119. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  120. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/py.typed +0 -0
  121. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  122. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/retry.py +0 -0
  123. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  124. {cmpnd-0.50.0 → cmpnd-0.52.0}/ingest/pyproject.toml +0 -0
  125. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/audit-sdist.sh +0 -0
  126. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/capture_review_run.py +0 -0
  127. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/check-pip-install.sh +0 -0
  128. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/check_release_artifacts.py +0 -0
  129. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/fixtures/review_run.json.gz +0 -0
  130. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/gepa_resume_bug.py +0 -0
  131. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/release-stress.sh +0 -0
  132. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/require_version_bump.py +0 -0
  133. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/seed_review_run.py +0 -0
  134. {cmpnd-0.50.0 → cmpnd-0.52.0}/scripts/test-in-linux.sh +0 -0
  135. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/__init__.pyi +0 -0
  136. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  137. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  138. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/utils/__init__.pyi +0 -0
  139. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/utils/callback.pyi +0 -0
  140. {cmpnd-0.50.0 → cmpnd-0.52.0}/stubs/dspy/utils/dummies.pyi +0 -0
  141. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/__init__.py +0 -0
  142. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_deployment_signature_helpers.py +0 -0
  143. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_exporter_helpers.py +0 -0
  144. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_fake_clock.py +0 -0
  145. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_identity_helpers.py +0 -0
  146. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_resolve_refs.py +0 -0
  147. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/_traced_run.py +0 -0
  148. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/conftest.py +0 -0
  149. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/__init__.py +0 -0
  150. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/committee_task.py +0 -0
  151. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/conftest.py +0 -0
  152. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  153. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  154. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/fake_lm.py +0 -0
  155. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/helpers.py +0 -0
  156. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/target_capabilities.py +0 -0
  157. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_assessments_cli.py +0 -0
  158. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_capture_prompts.py +0 -0
  159. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_composite_module.py +0 -0
  160. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  161. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_execute.py +0 -0
  162. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_pandas.py +0 -0
  163. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_deploy_programs.py +0 -0
  164. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_edge_cases.py +0 -0
  165. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_example_hash.py +0 -0
  166. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_gepa_optimization.py +0 -0
  167. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_interpreter_spans.py +0 -0
  168. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_lm_accuracy.py +0 -0
  169. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_module_tracing.py +0 -0
  170. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimization_lineage.py +0 -0
  171. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  172. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_failures.py +0 -0
  173. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_loop.py +0 -0
  174. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  175. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  176. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_parallel_export.py +0 -0
  177. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_project_attribution.py +0 -0
  178. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_react_tool_spans.py +0 -0
  179. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_save_load.py +0 -0
  180. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_trace_structure.py +0 -0
  181. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_traces_read.py +0 -0
  182. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_user_attribution.py +0 -0
  183. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/e2e/test_valsets_cli.py +0 -0
  184. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  185. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  186. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  187. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  188. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  189. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  190. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  191. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  192. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  193. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/10_react.json +0 -0
  194. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/11_refine.json +0 -0
  195. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/12_retrieve.json +0 -0
  196. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/13_knn.json +0 -0
  197. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/14_parallel.json +0 -0
  198. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/identity_vectors/README.md +0 -0
  199. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/ingest_conformance.py +0 -0
  200. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/__init__.py +0 -0
  201. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/authored_optimize/judge.py +0 -0
  202. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  203. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/conftest.py +0 -0
  204. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  205. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/hosted_optimize_probe.py +0 -0
  206. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/optimization_run_probe.py +0 -0
  207. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  208. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/test_logs_renders_traces.py +0 -0
  209. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/test_optimization_run.py +0 -0
  210. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/test_optimizing_progress.py +0 -0
  211. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/integration/test_unhappy_path.py +0 -0
  212. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/__init__.py +0 -0
  213. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/__main__.py +0 -0
  214. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/drain.py +0 -0
  215. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/ingest.py +0 -0
  216. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/latency_transport.py +0 -0
  217. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/rlm_shape.py +0 -0
  218. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/rlm_size_report.py +0 -0
  219. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/sweep.py +0 -0
  220. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/test_rlm_shape.py +0 -0
  221. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/load/test_rlm_size_report.py +0 -0
  222. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/__init__.py +0 -0
  223. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/conftest.py +0 -0
  224. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/seed_parity.py +0 -0
  225. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_auth.py +0 -0
  226. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_datasets.py +0 -0
  227. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_deployments.py +0 -0
  228. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_evals.py +0 -0
  229. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_health.py +0 -0
  230. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_modules.py +0 -0
  231. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_optimizations.py +0 -0
  232. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_programs.py +0 -0
  233. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_signatures.py +0 -0
  234. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_trace_streaming.py +0 -0
  235. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/parity/test_traces.py +0 -0
  236. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/span_reference_fixture.py +0 -0
  237. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/__init__.py +0 -0
  238. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/_provider.py +0 -0
  239. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/_readiness.py +0 -0
  240. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/_reliability.py +0 -0
  241. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/_result.py +0 -0
  242. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/mint_bedrock_token.py +0 -0
  243. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_deploy_programs.py +0 -0
  244. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_multi_client_stress.py +0 -0
  245. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_optimize_client_committee.py +0 -0
  246. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_optimize_loop.py +0 -0
  247. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_optimize_loop_wasm.py +0 -0
  248. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_optimize_stress.py +0 -0
  249. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_provider_roles.py +0 -0
  250. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_readiness.py +0 -0
  251. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_real_provider_twins.py +0 -0
  252. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_reliability.py +0 -0
  253. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_reliability_classify.py +0 -0
  254. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_rlm_wasm.py +0 -0
  255. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/stress/test_trace_search.py +0 -0
  256. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_adapter_reentrancy.py +0 -0
  257. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_assessments_api.py +0 -0
  258. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_authored.py +0 -0
  259. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_authored_bundle_collisions.py +0 -0
  260. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_authored_named_models.py +0 -0
  261. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_callback.py +0 -0
  262. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_candidate_lineage.py +0 -0
  263. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/__init__.py +0 -0
  264. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/conftest.py +0 -0
  265. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_admin.py +0 -0
  266. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_api_client.py +0 -0
  267. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_assessments.py +0 -0
  268. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_auth.py +0 -0
  269. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_credentials.py +0 -0
  270. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_datasets.py +0 -0
  271. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_deployment_runs.py +0 -0
  272. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_deployments.py +0 -0
  273. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_evals.py +0 -0
  274. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_login.py +0 -0
  275. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_main.py +0 -0
  276. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_optimizations.py +0 -0
  277. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_org.py +0 -0
  278. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_pagination.py +0 -0
  279. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_parity.py +0 -0
  280. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_programs.py +0 -0
  281. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_provider_credentials.py +0 -0
  282. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_schema_sample.py +0 -0
  283. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_shell.py +0 -0
  284. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_signatures.py +0 -0
  285. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_tool_servers.py +0 -0
  286. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_traces.py +0 -0
  287. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  288. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_tree_help.py +0 -0
  289. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cli/test_valsets.py +0 -0
  290. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_client_floor.py +0 -0
  291. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_clustering/__init__.py +0 -0
  292. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_clustering/conftest.py +0 -0
  293. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_clustering/test_edge_cases.py +0 -0
  294. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  295. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_clustering/test_type_conversion.py +0 -0
  296. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_cmp551_grouping_identity.py +0 -0
  297. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_configuration.py +0 -0
  298. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_context.py +0 -0
  299. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_context_propagation.py +0 -0
  300. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_dataset_polling.py +0 -0
  301. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_dataset_sync.py +0 -0
  302. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_datasets.py +0 -0
  303. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_decision_client_spans.py +0 -0
  304. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_decorators.py +0 -0
  305. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deployment_metadata.py +0 -0
  306. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deployment_runs.py +0 -0
  307. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_deployments_read.py +0 -0
  308. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_eval.py +0 -0
  309. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_eval_example_attribution.py +0 -0
  310. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_eval_start.py +0 -0
  311. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_eval_trace_grouping.py +0 -0
  312. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_exception_paths.py +0 -0
  313. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_execute.py +0 -0
  314. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_exporter.py +0 -0
  315. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_exporter_program_names.py +0 -0
  316. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_exporter_queue.py +0 -0
  317. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_exporter_real.py +0 -0
  318. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_fake_lm.py +0 -0
  319. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_gepa_callback.py +0 -0
  320. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_gepa_integration.py +0 -0
  321. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_gepa_output_normalization.py +0 -0
  322. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_gepa_resume.py +0 -0
  323. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_identity.py +0 -0
  324. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_imaging.py +0 -0
  325. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_import_weight.py +0 -0
  326. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_ingest_conformance.py +0 -0
  327. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_ingest_second_producer.py +0 -0
  328. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_integration.py +0 -0
  329. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_interpreter_callback.py +0 -0
  330. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_ir_encoder_properties.py +0 -0
  331. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_ir_golden_vectors.py +0 -0
  332. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_ir_roundtrip.py +0 -0
  333. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_lm15_native_calls.py +0 -0
  334. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_lm_configuration.py +0 -0
  335. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_lm_usage_shapes.py +0 -0
  336. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_mcp_tools.py +0 -0
  337. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_models.py +0 -0
  338. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_multi_client_stress_readiness.py +0 -0
  339. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimization_progress.py +0 -0
  340. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimization_start.py +0 -0
  341. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_budget.py +0 -0
  342. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_lift.py +0 -0
  343. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_lms.py +0 -0
  344. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_proposer.py +0 -0
  345. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_reflection_lm.py +0 -0
  346. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_optimize_terminal_failure.py +0 -0
  347. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_packaging.py +0 -0
  348. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_packaging_callable_source.py +0 -0
  349. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_packaging_mcp_tools.py +0 -0
  350. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_packaging_program_source.py +0 -0
  351. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_poll_until.py +0 -0
  352. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_program_lineage_persist.py +0 -0
  353. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_project_payload.py +0 -0
  354. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_real_provider_twins_readiness.py +0 -0
  355. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_reflector_properties.py +0 -0
  356. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_reflector_smoke.py +0 -0
  357. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_release_stress_script.py +0 -0
  358. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_repro_reactv2_bugs.py +0 -0
  359. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_require_version_bump.py +0 -0
  360. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_retry.py +0 -0
  361. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_reversible_failures.py +0 -0
  362. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_rlm_patch.py +0 -0
  363. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_run_attribution_paths.py +0 -0
  364. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_runtime_tools.py +0 -0
  365. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_schemas.py +0 -0
  366. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_seed_review_run.py +0 -0
  367. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_signature_inputs.py +0 -0
  368. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_span_references.py +0 -0
  369. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_span_sent_once.py +0 -0
  370. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_system_one.py +0 -0
  371. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_trace_context_concurrency.py +0 -0
  372. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_trace_fact_wire_contract.py +0 -0
  373. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_trace_facts.py +0 -0
  374. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_trace_render.py +0 -0
  375. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_traces_read.py +0 -0
  376. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_tracked_gepa.py +0 -0
  377. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_tracker_enrich.py +0 -0
  378. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_truncation.py +0 -0
  379. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_upload_auth_headers.py +0 -0
  380. {cmpnd-0.50.0 → cmpnd-0.52.0}/tests/test_valsets_api.py +0 -0
  381. {cmpnd-0.50.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.50.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
@@ -88,6 +87,24 @@ Auth: set CMPND_API_KEY and (optionally) CMPND_ENDPOINT, or pass --api-key /
88
87
  """
89
88
 
90
89
 
90
+ def parse(parser: argparse.ArgumentParser, argv: list[str]) -> argparse.Namespace:
91
+ """Parse ``argv``, and give a late positional the one word argparse could not place.
92
+
93
+ argparse fills optional positionals from the first run of bare words, so in
94
+ ``cmpnd deploy program.py --entrypoint qa capital-qa`` the program name comes too
95
+ late and is left over. A command that sets ``_late_positional`` takes one such
96
+ word into that argument when it is still empty. Anything else left over is the
97
+ usual usage error.
98
+ """
99
+ args, extras = parser.parse_known_args(argv)
100
+ late = getattr(args, "_late_positional", None)
101
+ if late and len(extras) == 1 and not extras[0].startswith("-") and getattr(args, late) is None:
102
+ setattr(args, late, extras.pop())
103
+ if extras:
104
+ parser.error("unrecognized arguments: " + " ".join(extras))
105
+ return args
106
+
107
+
91
108
  def main() -> None:
92
109
  parser = tree_help.TreeHelpParser(
93
110
  prog="cmpnd",
@@ -165,7 +182,7 @@ def main() -> None:
165
182
  # Top-level Docker-style shortcuts (human-readable by default; --json opts in)
166
183
  top.register(subparsers)
167
184
 
168
- args = parser.parse_args()
185
+ args = parse(parser, sys.argv[1:])
169
186
 
170
187
  if not args.resource:
171
188
  # Bare `cmpnd` drops into an interactive Python shell with platform
@@ -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
@@ -21,15 +22,25 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
21
22
 
22
23
  create = sub.add_parser(
23
24
  "create",
24
- help="Create a program and print its id",
25
+ help="Create a program with a name",
25
26
  description=(
26
- "Ask the platform for a new program id (p_…) and print it on stdout. Declare it "
27
- "with `cmpnd deploy --program-id`, `cmpnd.configure(program_id=...)` or "
28
- "CMPND_PROGRAM_ID so deployments, traces and optimization runs carry it. Each "
29
- "call creates a new program."
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=...)."
30
32
  ),
31
33
  )
32
- create.add_argument("--name", default=None, help="Display name (need not be unique)")
34
+ create.add_argument(
35
+ "name", nargs="?", default=None, metavar="PROGRAM_NAME", help="Program name, unique in your organization"
36
+ )
37
+ # Deprecated program id input: --name, the display name of an unnamed program, goes when it is removed.
38
+ create.add_argument(
39
+ "--name",
40
+ dest="display_name",
41
+ default=None,
42
+ help=argparse.SUPPRESS,
43
+ )
33
44
  create.add_argument("--json", action="store_true", help="Emit the created program as JSON instead of its id")
34
45
  create.set_defaults(func=handle_create)
35
46
 
@@ -87,12 +98,20 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
87
98
 
88
99
 
89
100
  def handle_create(client: api_client.ApiClient, args: Any) -> Any:
90
- """Create a program. Prints the bare id on stdout so a script can capture it
91
- (``PROGRAM_ID=$(cmpnd programs create --name triage)``) and says what it made on
92
- stderr; ``--json`` returns the whole row 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."""
93
106
  from ... import programs
94
107
 
95
- row = programs.send_create(client, name=args.name)
108
+ if args.name is not None:
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())
114
+ row = programs.send_create(client, name=args.display_name)
96
115
  if getattr(args, "json", False):
97
116
  return row
98
117
  print(row["id"])
@@ -101,6 +120,36 @@ def handle_create(client: api_client.ApiClient, args: Any) -> Any:
101
120
  return None
102
121
 
103
122
 
123
+ def _create_named(client: api_client.ApiClient, args: Any) -> Any:
124
+ """Create the program named ``args.name``, and refuse a name that already has one."""
125
+ from ... import programs
126
+ from . import top
127
+
128
+ if args.display_name is not None:
129
+ raise api_client.CliError("give a program name or --name, not both: --name is the older display name")
130
+ try:
131
+ answer = programs.send_resolve(client, args.name)
132
+ except ValueError as exc:
133
+ raise api_client.CliError(str(exc)) from exc
134
+ if answer is None:
135
+ raise api_client.CliError(
136
+ "This server has no program names, so it cannot create a program from a program name. A serve from "
137
+ "before program names, such as self-host release 2026-001, needs no program first: "
138
+ f"`{top._hint_program_name('deploy', source='SOURCE', name='PROGRAM_NAME')}` deploys there without "
139
+ "a program id."
140
+ )
141
+ if not answer.get("created"):
142
+ raise api_client.CliError(
143
+ f"the program name {args.name!r} already has a program, {answer['program_id']}. "
144
+ f"Deploy under it with `{top._hint_program_name('deploy', source='SOURCE', name=args.name)}`."
145
+ )
146
+ if getattr(args, "json", False):
147
+ return answer
148
+ print(answer["program_id"])
149
+ print(f"created program {answer['program_id']} named {args.name}", file=sys.stderr)
150
+ return None
151
+
152
+
104
153
  def handle_list(client: api_client.ApiClient, args: Any) -> Any:
105
154
  params: dict[str, str] = pagination.wire(args, "per_page", as_str=True)
106
155
  params["order_by"] = args.order_by