orizu 0.5.19 → 0.5.21

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 (378) hide show
  1. package/README.md +23 -0
  2. package/dist/archive-artifacts-cli.d.ts +50 -0
  3. package/dist/archive-artifacts-cli.d.ts.map +1 -0
  4. package/dist/artifact-archive.d.ts +48 -0
  5. package/dist/artifact-archive.d.ts.map +1 -0
  6. package/dist/artifact-pull.d.ts +22 -0
  7. package/dist/artifact-pull.d.ts.map +1 -0
  8. package/dist/banner.d.ts +3 -0
  9. package/dist/banner.d.ts.map +1 -0
  10. package/dist/connectors-cli.d.ts +31 -0
  11. package/dist/connectors-cli.d.ts.map +1 -0
  12. package/dist/credentials.d.ts +46 -0
  13. package/dist/credentials.d.ts.map +1 -0
  14. package/dist/csv.d.ts +49 -0
  15. package/dist/csv.d.ts.map +1 -0
  16. package/dist/dataset-download.d.ts +6 -0
  17. package/dist/dataset-download.d.ts.map +1 -0
  18. package/dist/dataset-edit-rows.d.ts +10 -0
  19. package/dist/dataset-edit-rows.d.ts.map +1 -0
  20. package/dist/dataset-upload-snapshot.d.ts +13 -0
  21. package/dist/dataset-upload-snapshot.d.ts.map +1 -0
  22. package/dist/daytona-slice-rehearsal.d.ts +89 -0
  23. package/dist/daytona-slice-rehearsal.d.ts.map +1 -0
  24. package/dist/daytona-slice.d.ts +106 -0
  25. package/dist/daytona-slice.d.ts.map +1 -0
  26. package/dist/deploy-key-merge-core.d.ts +121 -0
  27. package/dist/deploy-key-merge-core.d.ts.map +1 -0
  28. package/dist/diff-comments-cli.d.ts +12 -0
  29. package/dist/diff-comments-cli.d.ts.map +1 -0
  30. package/dist/diff-comments-cli.js +21 -2
  31. package/dist/egress-allowlist-cli.d.ts +23 -0
  32. package/dist/egress-allowlist-cli.d.ts.map +1 -0
  33. package/dist/egress-policy.d.ts +108 -0
  34. package/dist/egress-policy.d.ts.map +1 -0
  35. package/dist/error-response.d.ts +9 -0
  36. package/dist/error-response.d.ts.map +1 -0
  37. package/dist/file-parser.d.ts +5 -0
  38. package/dist/file-parser.d.ts.map +1 -0
  39. package/dist/gepa-engine-dispatch.d.ts +9 -0
  40. package/dist/gepa-engine-dispatch.d.ts.map +1 -0
  41. package/dist/gepa-engine-dispatch.js +307 -0
  42. package/dist/gepa-python-command.d.ts +6 -0
  43. package/dist/gepa-python-command.d.ts.map +1 -0
  44. package/dist/gepa-python-command.js +26 -0
  45. package/dist/gepa-python-paths.d.ts +6 -0
  46. package/dist/gepa-python-paths.d.ts.map +1 -0
  47. package/dist/gepa-python-paths.js +42 -0
  48. package/dist/git-credential.d.ts +69 -0
  49. package/dist/git-credential.d.ts.map +1 -0
  50. package/dist/git-recovery-environment.d.ts +31 -0
  51. package/dist/git-recovery-environment.d.ts.map +1 -0
  52. package/dist/github-setup.d.ts +122 -0
  53. package/dist/github-setup.d.ts.map +1 -0
  54. package/dist/global-flags.d.ts +12 -0
  55. package/dist/global-flags.d.ts.map +1 -0
  56. package/dist/help.d.ts +46 -0
  57. package/dist/help.d.ts.map +1 -0
  58. package/dist/help.js +93 -25
  59. package/dist/hosted-boot.d.ts +273 -0
  60. package/dist/hosted-boot.d.ts.map +1 -0
  61. package/dist/hosted-bootstrap-rehearsal.d.ts +86 -0
  62. package/dist/hosted-bootstrap-rehearsal.d.ts.map +1 -0
  63. package/dist/hosted-bootstrap.d.ts +188 -0
  64. package/dist/hosted-bootstrap.d.ts.map +1 -0
  65. package/dist/hosted-broker-server.d.ts +50 -0
  66. package/dist/hosted-broker-server.d.ts.map +1 -0
  67. package/dist/hosted-git-http-server.d.ts +36 -0
  68. package/dist/hosted-git-http-server.d.ts.map +1 -0
  69. package/dist/hosted-harness-claude.d.ts +195 -0
  70. package/dist/hosted-harness-claude.d.ts.map +1 -0
  71. package/dist/hosted-harness-opencode.d.ts +227 -0
  72. package/dist/hosted-harness-opencode.d.ts.map +1 -0
  73. package/dist/hosted-harness.d.ts +118 -0
  74. package/dist/hosted-harness.d.ts.map +1 -0
  75. package/dist/hosted-harvest.d.ts +68 -0
  76. package/dist/hosted-harvest.d.ts.map +1 -0
  77. package/dist/hosted-headless.d.ts +72 -0
  78. package/dist/hosted-headless.d.ts.map +1 -0
  79. package/dist/hosted-loop-lifecycle.d.ts +206 -0
  80. package/dist/hosted-loop-lifecycle.d.ts.map +1 -0
  81. package/dist/hosted-loop.d.ts +170 -0
  82. package/dist/hosted-loop.d.ts.map +1 -0
  83. package/dist/hosted-run-event-sink.d.ts +222 -0
  84. package/dist/hosted-run-event-sink.d.ts.map +1 -0
  85. package/dist/hosted-runtime-assets.d.ts +186 -0
  86. package/dist/hosted-runtime-assets.d.ts.map +1 -0
  87. package/dist/hosted-session-cli.d.ts +258 -0
  88. package/dist/hosted-session-cli.d.ts.map +1 -0
  89. package/dist/hosted-skill-staging.d.ts +73 -0
  90. package/dist/hosted-skill-staging.d.ts.map +1 -0
  91. package/dist/http.d.ts +8 -0
  92. package/dist/http.d.ts.map +1 -0
  93. package/dist/index.d.ts +22 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +119 -129
  96. package/dist/instruction-set-gepa-launch.d.ts +3 -0
  97. package/dist/instruction-set-gepa-launch.d.ts.map +1 -0
  98. package/dist/instruction-set-gepa-launch.js +15 -0
  99. package/dist/instruction-set-loader.d.ts +6 -0
  100. package/dist/instruction-set-loader.d.ts.map +1 -0
  101. package/dist/instruction-set-loader.js +59 -0
  102. package/dist/instruction-set-manifest.d.ts +14 -0
  103. package/dist/instruction-set-manifest.d.ts.map +1 -0
  104. package/dist/instruction-set-manifest.js +162 -0
  105. package/dist/instruction-sets-cli.d.ts +40 -0
  106. package/dist/instruction-sets-cli.d.ts.map +1 -0
  107. package/dist/instruction-sets-cli.js +361 -0
  108. package/dist/json-response.d.ts +4 -0
  109. package/dist/json-response.d.ts.map +1 -0
  110. package/dist/jsonl-stream.d.ts +8 -0
  111. package/dist/jsonl-stream.d.ts.map +1 -0
  112. package/dist/kill-switch-cli.d.ts +30 -0
  113. package/dist/kill-switch-cli.d.ts.map +1 -0
  114. package/dist/loopback-serve.d.ts +25 -0
  115. package/dist/loopback-serve.d.ts.map +1 -0
  116. package/dist/manifests-cli.d.ts +22 -0
  117. package/dist/manifests-cli.d.ts.map +1 -0
  118. package/dist/markdown-report-input.d.ts +7 -0
  119. package/dist/markdown-report-input.d.ts.map +1 -0
  120. package/dist/markdown-report-input.js +15 -1
  121. package/dist/merge-job.d.ts +155 -0
  122. package/dist/merge-job.d.ts.map +1 -0
  123. package/dist/model-configs-cli.d.ts +19 -0
  124. package/dist/model-configs-cli.d.ts.map +1 -0
  125. package/dist/model-configs-cli.js +104 -0
  126. package/dist/optimization-export-cli.d.ts +19 -0
  127. package/dist/optimization-export-cli.d.ts.map +1 -0
  128. package/dist/optimizations-list-cli.d.ts +20 -0
  129. package/dist/optimizations-list-cli.d.ts.map +1 -0
  130. package/dist/optimizations-promote-cli.d.ts +8 -0
  131. package/dist/optimizations-promote-cli.d.ts.map +1 -0
  132. package/dist/optimizations-promote-cli.js +34 -0
  133. package/dist/option-validation.d.ts +15 -0
  134. package/dist/option-validation.d.ts.map +1 -0
  135. package/dist/preview-runtime.d.ts +63 -0
  136. package/dist/preview-runtime.d.ts.map +1 -0
  137. package/dist/prompt-draft-push.d.ts +60 -0
  138. package/dist/prompt-draft-push.d.ts.map +1 -0
  139. package/dist/prompt-label-cli.d.ts +11 -0
  140. package/dist/prompt-label-cli.d.ts.map +1 -0
  141. package/dist/prompt-label-cli.js +29 -0
  142. package/dist/prompt-length-wire.d.ts +28 -0
  143. package/dist/prompt-length-wire.d.ts.map +1 -0
  144. package/dist/prompt-length-wire.js +2 -2
  145. package/dist/prompt-report-cli.d.ts +10 -0
  146. package/dist/prompt-report-cli.d.ts.map +1 -0
  147. package/dist/prompt-report-cli.js +2 -2
  148. package/dist/prompt-summary-table.d.ts +15 -0
  149. package/dist/prompt-summary-table.d.ts.map +1 -0
  150. package/dist/prompt-summary-table.js +6 -0
  151. package/dist/registration-tag-warning.d.ts +32 -0
  152. package/dist/registration-tag-warning.d.ts.map +1 -0
  153. package/dist/report-comments-cli.d.ts +16 -0
  154. package/dist/report-comments-cli.d.ts.map +1 -0
  155. package/dist/report-markdown-blankness.d.ts +2 -0
  156. package/dist/report-markdown-blankness.d.ts.map +1 -0
  157. package/dist/report-markdown-blankness.js +6 -0
  158. package/dist/report-replacement-warning.d.ts +17 -0
  159. package/dist/report-replacement-warning.d.ts.map +1 -0
  160. package/dist/report-replacement-warning.js +31 -0
  161. package/dist/repository-backup-core.d.ts +225 -0
  162. package/dist/repository-backup-core.d.ts.map +1 -0
  163. package/dist/repository-recovery-manifest.d.ts +83 -0
  164. package/dist/repository-recovery-manifest.d.ts.map +1 -0
  165. package/dist/run-event-digest.d.ts +74 -0
  166. package/dist/run-event-digest.d.ts.map +1 -0
  167. package/dist/runner-dir-verify.d.ts +66 -0
  168. package/dist/runner-dir-verify.d.ts.map +1 -0
  169. package/dist/runner-instruction-set-contract.d.ts +24 -0
  170. package/dist/runner-instruction-set-contract.d.ts.map +1 -0
  171. package/dist/runner-instruction-set-contract.js +50 -0
  172. package/dist/sandbox-hygiene.d.ts +45 -0
  173. package/dist/sandbox-hygiene.d.ts.map +1 -0
  174. package/dist/sandbox-provider.d.ts +193 -0
  175. package/dist/sandbox-provider.d.ts.map +1 -0
  176. package/dist/scorer-draft-push.d.ts +50 -0
  177. package/dist/scorer-draft-push.d.ts.map +1 -0
  178. package/dist/scorers-cli.d.ts +20 -0
  179. package/dist/scorers-cli.d.ts.map +1 -0
  180. package/dist/scorers-cli.js +22 -0
  181. package/dist/scorers-verify-parity-bridge.d.ts +16 -0
  182. package/dist/scorers-verify-parity-bridge.d.ts.map +1 -0
  183. package/dist/scorers-verify-parity-bridge.js +90 -0
  184. package/dist/scorers-verify-parity.d.ts +81 -0
  185. package/dist/scorers-verify-parity.d.ts.map +1 -0
  186. package/dist/scorers-verify-parity.js +502 -0
  187. package/dist/scores-accept-cli.d.ts +21 -0
  188. package/dist/scores-accept-cli.d.ts.map +1 -0
  189. package/dist/secret-redaction.d.ts +47 -0
  190. package/dist/secret-redaction.d.ts.map +1 -0
  191. package/dist/session-timeline.d.ts +54 -0
  192. package/dist/session-timeline.d.ts.map +1 -0
  193. package/dist/setup-prompt.d.ts +5 -0
  194. package/dist/setup-prompt.d.ts.map +1 -0
  195. package/dist/skill-installer.d.ts +68 -0
  196. package/dist/skill-installer.d.ts.map +1 -0
  197. package/dist/skilled-proposer-launch.d.ts +7 -0
  198. package/dist/skilled-proposer-launch.d.ts.map +1 -0
  199. package/dist/skilled-proposer-launch.js +60 -0
  200. package/dist/smoke.d.ts +102 -0
  201. package/dist/smoke.d.ts.map +1 -0
  202. package/dist/start-intent.d.ts +12 -0
  203. package/dist/start-intent.d.ts.map +1 -0
  204. package/dist/task-assignment-manifest.d.ts +15 -0
  205. package/dist/task-assignment-manifest.d.ts.map +1 -0
  206. package/dist/task-create-error.d.ts +18 -0
  207. package/dist/task-create-error.d.ts.map +1 -0
  208. package/dist/team-connectors-cli.d.ts +29 -0
  209. package/dist/team-connectors-cli.d.ts.map +1 -0
  210. package/dist/types.d.ts +39 -0
  211. package/dist/types.d.ts.map +1 -0
  212. package/dist/vercel-sandbox-provider.d.ts +156 -0
  213. package/dist/vercel-sandbox-provider.d.ts.map +1 -0
  214. package/dist/workbench-cli.d.ts +233 -0
  215. package/dist/workbench-cli.d.ts.map +1 -0
  216. package/dist/workspace-sync.d.ts +207 -0
  217. package/dist/workspace-sync.d.ts.map +1 -0
  218. package/dist/workspace.d.ts +92 -0
  219. package/dist/workspace.d.ts.map +1 -0
  220. package/dist/zip-draft-push.d.ts +55 -0
  221. package/dist/zip-draft-push.d.ts.map +1 -0
  222. package/package.json +15 -2
  223. package/requirements/README.md +138 -0
  224. package/requirements/skilled-proposer.in +66 -0
  225. package/requirements/skilled-proposer.lock +265 -0
  226. package/scripts/build-cli-dist.mjs +30 -0
  227. package/scripts/ensure-skilled-proposer-venv.mjs +5 -0
  228. package/scripts/orizu-source-checkout.d.mts +1 -0
  229. package/scripts/orizu-source-checkout.mjs +10 -0
  230. package/scripts/refresh-skilled-proposer-lock.mjs +256 -0
  231. package/scripts/vendor-gepa-python.mjs +187 -4
  232. package/src/diff-comments-cli.ts +41 -3
  233. package/src/gepa-engine-dispatch.ts +340 -0
  234. package/src/gepa-python-command.ts +31 -0
  235. package/src/gepa-python-paths.ts +56 -0
  236. package/src/help.ts +95 -25
  237. package/src/index.ts +131 -166
  238. package/src/instruction-set-gepa-launch.ts +28 -0
  239. package/src/instruction-set-loader.ts +37 -0
  240. package/src/instruction-set-manifest.ts +120 -0
  241. package/src/instruction-sets-cli.ts +306 -0
  242. package/src/markdown-report-input.ts +19 -1
  243. package/src/model-configs-cli.ts +119 -0
  244. package/src/optimizations-promote-cli.ts +41 -0
  245. package/src/prompt-label-cli.ts +55 -0
  246. package/src/prompt-length-wire.ts +1 -1
  247. package/src/prompt-report-cli.ts +2 -2
  248. package/src/prompt-summary-table.ts +12 -0
  249. package/src/report-markdown-blankness.ts +6 -0
  250. package/src/report-replacement-warning.ts +35 -0
  251. package/src/runner-instruction-set-contract.ts +64 -0
  252. package/src/scorers-cli.ts +40 -0
  253. package/src/scorers-verify-parity-bridge.ts +90 -0
  254. package/src/scorers-verify-parity.ts +564 -0
  255. package/src/skilled-proposer-launch.ts +89 -0
  256. package/src/skilled-proposer-venv-manager.mjs +757 -0
  257. package/tsconfig.json +2 -0
  258. package/vendor/gepa-python/LICENSE +7 -0
  259. package/vendor/gepa-python/manifest.json +107 -0
  260. package/vendor/gepa-python/src/gepa/__init__.py +22 -0
  261. package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
  262. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
  263. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  264. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
  265. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
  266. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
  267. package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
  268. package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
  269. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
  270. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
  271. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
  272. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
  273. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  274. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
  275. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
  276. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  277. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  278. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  279. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  280. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  281. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  282. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  283. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  284. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  285. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  286. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
  287. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
  288. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
  289. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
  290. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
  291. package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
  292. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
  293. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  294. package/vendor/gepa-python/src/gepa/api.py +468 -0
  295. package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
  296. package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
  297. package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
  298. package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
  299. package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
  300. package/vendor/gepa-python/src/gepa/core/result.py +271 -0
  301. package/vendor/gepa-python/src/gepa/core/state.py +706 -0
  302. package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
  303. package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
  304. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
  305. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
  306. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
  307. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  308. package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
  309. package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
  310. package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
  311. package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
  312. package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
  313. package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
  314. package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
  315. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
  316. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
  317. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
  318. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
  319. package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
  320. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
  321. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
  322. package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
  323. package/vendor/gepa-python/src/gepa/image.py +104 -0
  324. package/vendor/gepa-python/src/gepa/lm.py +261 -0
  325. package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
  326. package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
  327. package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
  328. package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
  329. package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
  330. package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
  331. package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
  332. package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
  333. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
  334. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
  335. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
  336. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
  337. package/vendor/gepa-python/src/gepa/py.typed +0 -0
  338. package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
  339. package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
  340. package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
  341. package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
  342. package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
  343. package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
  344. package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
  345. package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
  346. package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
  347. package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
  348. package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
  349. package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
  350. package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
  351. package/vendor/gepa-python/src/gepa/visualization.py +359 -0
  352. package/vendor/orizu-gepa/pyproject.toml +18 -0
  353. package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +9 -0
  354. package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
  355. package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +138 -0
  356. package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +666 -0
  357. package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
  358. package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +269 -0
  359. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +52 -0
  360. package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
  361. package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +186 -0
  362. package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +721 -0
  363. package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +381 -0
  364. package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +55 -0
  365. package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +203 -0
  366. package/vendor/orizu-gepa-python/pyproject.toml +1 -1
  367. package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
  368. package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +52 -7
  369. package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +52 -0
  370. package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +10 -5
  371. package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +323 -68
  372. package/vendor/orizu-gepa-python/src/orizu_gepa/runner.py +207 -13
  373. package/vendor/skills/orizu-cli/SKILL.md +3 -1
  374. package/vendor/skills/orizu-cli/references/cli-reference.md +85 -1
  375. package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +303 -0
  376. package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
  377. package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +26 -1
  378. package/vendor/skills/orizu-cli/references/prompt-control-plane.md +113 -10
@@ -0,0 +1,381 @@
1
+ """Typed DSPy bridge for the opt-in skilled-proposer integration.
2
+
3
+ This module deliberately owns proposal-LM observability. It does not use
4
+ ``dspy.LM`` or LiteLLM: every completion reaches the frozen provider transport
5
+ through ``complete_reflection_messages`` and is recorded before DSPy sees its
6
+ response.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import atexit
12
+ import dataclasses
13
+ import json
14
+ import os
15
+ import shutil
16
+ import tempfile
17
+ import uuid
18
+ from dataclasses import dataclass, field
19
+ from pathlib import Path
20
+ from typing import TYPE_CHECKING, Any
21
+ from urllib.parse import urlparse
22
+
23
+ try:
24
+ import dspy
25
+ except ModuleNotFoundError as error:
26
+ if error.name != "dspy":
27
+ raise
28
+ dspy = None
29
+
30
+ if TYPE_CHECKING:
31
+ import dspy as dspy_types
32
+
33
+ from orizu_gepa.reflection import ProviderCompletion, complete_reflection_messages
34
+ from orizu_gepa.optimizer import TextGepaConfig
35
+
36
+ _SELECTION_ENV = "ORIZU_CANDIDATE_PROPOSER"
37
+ _SELECTION_VALUE = "skilled-proposer"
38
+ _SUPPORTED_ROLES = {"system", "user", "assistant"}
39
+ _ALLOWED_DSPY_REQUEST_FIELDS = frozenset({"temperature", "max_tokens", "cache"})
40
+ _DspyBaseLM = dspy.BaseLM if dspy is not None else object
41
+
42
+
43
+ def _require_dspy() -> Any:
44
+ if dspy is None:
45
+ raise RuntimeError("ALI_1505_DSPY_UNAVAILABLE")
46
+ return dspy
47
+
48
+
49
+ def _usage_totals() -> dict[str, int]:
50
+ return {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
51
+
52
+
53
+ def _require_usage(usage: dict[str, int]) -> dict[str, int]:
54
+ try:
55
+ normalized = {name: int(usage[name]) for name in _usage_totals()}
56
+ except (KeyError, TypeError, ValueError) as error:
57
+ raise RuntimeError("ALI_1505_PROPOSAL_USAGE_INVALID") from error
58
+ if any(value < 0 for value in normalized.values()):
59
+ raise RuntimeError("ALI_1505_PROPOSAL_USAGE_INVALID")
60
+ return normalized
61
+
62
+
63
+ @dataclass
64
+ class ProposalCallBudget:
65
+ """The connector-owned proposal ledger; GEPA metric accounting is separate."""
66
+
67
+ max_calls: int | None = None
68
+ max_tokens: int | None = None
69
+ call_count: int = 0
70
+ usage: dict[str, int] = field(default_factory=_usage_totals)
71
+
72
+ def record(self, usage: dict[str, int] | None = None) -> None:
73
+ self.call_count += 1
74
+ if usage is None:
75
+ return
76
+ normalized = _require_usage(usage)
77
+ for name, value in normalized.items():
78
+ self.usage[name] += value
79
+
80
+ def has_safe_boundary_stop(self) -> bool:
81
+ return ((self.max_calls is not None and self.call_count >= self.max_calls) or
82
+ (self.max_tokens is not None and self.usage["total_tokens"] >= self.max_tokens))
83
+
84
+
85
+ class ProposalObservability:
86
+ """Durable per-provider-call proposal evidence and aggregate raw usage."""
87
+
88
+ def __init__(self, *, event_log_root: Path, durable_failure_root: Path, budget: ProposalCallBudget | None = None):
89
+ self.event_log_root = event_log_root
90
+ self.durable_failure_root = durable_failure_root
91
+ self.events: list[dict[str, Any]] = []
92
+ self.budget = budget or ProposalCallBudget()
93
+ self._temporary_root: Path | None = None
94
+
95
+ @classmethod
96
+ def local_for_test(
97
+ cls,
98
+ *,
99
+ event_log_root: Path | None = None,
100
+ durable_failure_root: Path | None = None,
101
+ ) -> "ProposalObservability":
102
+ root = Path(tempfile.mkdtemp(prefix="orizu-ali1505-proposal-events-"))
103
+ result = cls(
104
+ event_log_root=event_log_root or root / "events",
105
+ durable_failure_root=durable_failure_root or root / "durable-failures",
106
+ )
107
+ result._temporary_root = root
108
+ atexit.register(shutil.rmtree, root, ignore_errors=True)
109
+ return result
110
+
111
+ def bind_budget(self, budget: ProposalCallBudget) -> None:
112
+ self.budget = budget
113
+
114
+ def close(self) -> None:
115
+ if self._temporary_root is not None:
116
+ shutil.rmtree(self._temporary_root, ignore_errors=True)
117
+ self._temporary_root = None
118
+
119
+ def __del__(self) -> None:
120
+ self.close()
121
+
122
+ def _append_event(self, event: dict[str, Any]) -> None:
123
+ self.event_log_root.mkdir(parents=True, exist_ok=True)
124
+ with (self.event_log_root / "events.jsonl").open("a", encoding="utf-8") as handle:
125
+ handle.write(json.dumps(event, sort_keys=True) + "\n")
126
+ self.events.append(event)
127
+
128
+ def _write_durable_failure(self, *, code: str, detail: str, correlation_id: str | None = None) -> None:
129
+ try:
130
+ self.durable_failure_root.mkdir(parents=True, exist_ok=True)
131
+ payload: dict[str, Any] = {"source": "skilled_proposer", "code": code, "detail": detail}
132
+ if correlation_id is not None:
133
+ payload["correlation_id"] = correlation_id
134
+ (self.durable_failure_root / "latest.json").write_text(
135
+ json.dumps(payload, sort_keys=True) + "\n", encoding="utf-8",
136
+ )
137
+ except Exception:
138
+ # The original delivery failure remains the actionable error. A
139
+ # second durable-store failure cannot be made durable by retrying it.
140
+ return
141
+
142
+ def record_success(self, event: dict[str, Any], usage: dict[str, int]) -> None:
143
+ self.budget.record(usage)
144
+ self._append_event(event)
145
+
146
+ def record_provider_failure(
147
+ self,
148
+ event: dict[str, Any],
149
+ *,
150
+ code: str,
151
+ detail: str,
152
+ usage: dict[str, int] | None = None,
153
+ ) -> None:
154
+ self.budget.record(usage)
155
+ self._write_durable_failure(code=code, detail=detail, correlation_id=event.get("correlation_id"))
156
+ self._append_event(event)
157
+
158
+ def record_event_failure(self, error: Exception, *, correlation_id: str) -> None:
159
+ self._write_durable_failure(
160
+ code="proposal_observability_event_failed", detail=str(error), correlation_id=correlation_id,
161
+ )
162
+
163
+ def terminal_stats(self) -> dict[str, Any]:
164
+ return {"call_count": self.budget.call_count, "usage": dict(self.budget.usage)}
165
+
166
+ def terminal_lm_stats(self) -> dict[str, int]:
167
+ return {
168
+ "total_tokens_in": self.budget.usage["input_tokens"],
169
+ "total_tokens_out": self.budget.usage["output_tokens"],
170
+ "total_tokens": self.budget.usage["total_tokens"],
171
+ }
172
+
173
+ def write_terminal_lm_stats_artifact(self) -> str:
174
+ self.event_log_root.mkdir(parents=True, exist_ok=True)
175
+ path = self.event_log_root / "lm_stats.json"
176
+ path.write_text(json.dumps(self.terminal_lm_stats(), sort_keys=True) + "\n", encoding="utf-8")
177
+ return str(path)
178
+
179
+ def read_durable_failure(self) -> dict[str, Any]:
180
+ return json.loads((self.durable_failure_root / "latest.json").read_text(encoding="utf-8"))
181
+
182
+ def has_safe_boundary_stop(self) -> bool:
183
+ return self.budget.has_safe_boundary_stop()
184
+
185
+
186
+ def _reject(message: str, *, code: str = "proposal_dspy_request_rejected") -> Any:
187
+ return _require_dspy().LMError(message, code=code)
188
+
189
+
190
+ def _provider_messages(request: "dspy_types.LMRequest") -> list[dict[str, str]]:
191
+ if request.tools:
192
+ raise _reject("proposal_dspy_request_rejected: tools are not supported")
193
+ messages: list[dict[str, str]] = []
194
+ for message in request.messages:
195
+ dumped = message.model_dump()
196
+ role = dumped.get("role")
197
+ if role not in _SUPPORTED_ROLES:
198
+ raise _reject(f"proposal_dspy_request_rejected: unsupported message role {role!r}")
199
+ text_parts: list[str] = []
200
+ for part in dumped.get("parts", []):
201
+ if part.get("type") != "text" or not isinstance(part.get("text"), str):
202
+ raise _reject("proposal_dspy_request_rejected: only text message parts are supported")
203
+ text_parts.append(part["text"])
204
+ if not text_parts:
205
+ raise _reject("proposal_dspy_request_rejected: text messages must contain at least one text part")
206
+ messages.append({"role": role, "content": "".join(text_parts)})
207
+ return messages
208
+
209
+
210
+ def _request_config(request: "dspy_types.LMRequest", base: TextGepaConfig) -> TextGepaConfig:
211
+ config = request.config
212
+ unsupported = {
213
+ name: value
214
+ for name, value in config.model_dump().items()
215
+ if name not in _ALLOWED_DSPY_REQUEST_FIELDS and value not in (None, {})
216
+ }
217
+ if unsupported:
218
+ raise _reject("proposal_dspy_request_rejected: unsupported DSPy generation configuration")
219
+ cache = config.cache
220
+ if cache is not None and (getattr(cache, "enabled", False) or getattr(cache, "rollout_id", None) is not None):
221
+ raise _reject("proposal_dspy_cache_rejected: proposal response caching is disabled", code="proposal_dspy_cache_rejected")
222
+ changes: dict[str, Any] = {}
223
+ if config.temperature is not None:
224
+ changes["reflection_temperature"] = config.temperature
225
+ if config.max_tokens is not None:
226
+ if config.max_tokens <= 0:
227
+ raise _reject("proposal_dspy_request_rejected: max_tokens must be positive")
228
+ changes["reflection_max_tokens"] = config.max_tokens
229
+ return dataclasses.replace(base, **changes) if changes else base
230
+
231
+
232
+ def _loopback_endpoint(endpoint: str) -> str:
233
+ parsed = urlparse(endpoint)
234
+ if parsed.scheme not in {"http", "https"} or parsed.hostname not in {"127.0.0.1", "::1", "localhost"}:
235
+ raise ValueError("ALI_1505_BRIDGE_ENDPOINT_OVERRIDE_NOT_LOOPBACK")
236
+ if parsed.username or parsed.password:
237
+ raise ValueError("ALI_1505_BRIDGE_ENDPOINT_OVERRIDE_INVALID")
238
+ return endpoint
239
+
240
+
241
+ class OrizuSkilledProposerLM(_DspyBaseLM):
242
+ """A typed DSPy LM whose only completion path is Orizu's provider transport."""
243
+
244
+ forward_contract = "typed_lm"
245
+
246
+ def __init__(
247
+ self,
248
+ *,
249
+ config: TextGepaConfig,
250
+ observability: ProposalObservability,
251
+ endpoint_override: str | None = None,
252
+ ssl_cert_file: str | None = None,
253
+ ) -> None:
254
+ # Provider retries belong exclusively to the frozen transport. DSPy
255
+ # must not retry after a durable-event failure and create unrecorded
256
+ # duplicate proposal attempts.
257
+ _require_dspy().BaseLM.__init__(
258
+ self,
259
+ config.reflection_model,
260
+ temperature=config.reflection_temperature,
261
+ max_tokens=config.reflection_max_tokens,
262
+ cache=False,
263
+ num_retries=0,
264
+ )
265
+ self._config = config
266
+ self._observability = observability
267
+ self._endpoint_override = _loopback_endpoint(endpoint_override) if endpoint_override else None
268
+ self._ssl_cert_file = ssl_cert_file
269
+
270
+ def forward(self, request: "dspy_types.LMRequest") -> "dspy_types.LMResponse":
271
+ dspy_module = _require_dspy()
272
+ correlation_id = uuid.uuid4().hex
273
+ if request.model != self.model:
274
+ raise _reject(
275
+ "proposal_dspy_model_rejected: requested model differs from the configured reflection model",
276
+ code="proposal_dspy_model_rejected",
277
+ )
278
+ messages = _provider_messages(request)
279
+ config = _request_config(request, self._config)
280
+ try:
281
+ completion: ProviderCompletion = complete_reflection_messages(
282
+ model=self.model,
283
+ messages=messages,
284
+ config=config,
285
+ endpoint_override=self._endpoint_override,
286
+ ssl_cert_file=self._ssl_cert_file,
287
+ # The explicit loopback harness must never receive a real
288
+ # provider credential from this process.
289
+ api_key_override="loopback-test-key" if self._endpoint_override else None,
290
+ )
291
+ except Exception as error:
292
+ provider_code = getattr(error, "code", None)
293
+ failure_usage = getattr(error, "usage", None)
294
+ failure_event = {
295
+ "source": "skilled_proposer",
296
+ "status": "failure",
297
+ "attempt": 1,
298
+ "correlation_id": correlation_id,
299
+ "provider": "openai" if self.model.startswith("openai/") else "anthropic",
300
+ "cache_state": "disabled",
301
+ "failure_code": provider_code or "ALI_1505_PROPOSAL_TRANSPORT_FAILURE",
302
+ }
303
+ if failure_usage is not None:
304
+ failure_event["usage"] = failure_usage
305
+ try:
306
+ self._observability.record_provider_failure(
307
+ failure_event,
308
+ code="proposal_provider_transport_failed",
309
+ detail=str(error),
310
+ usage=failure_usage,
311
+ )
312
+ except Exception as event_error:
313
+ self._observability.record_event_failure(event_error, correlation_id=correlation_id)
314
+ raise RuntimeError("proposal_observability_event_failed") from event_error
315
+ raise dspy_module.LMError(
316
+ f"proposal_provider_transport_failed: {error}",
317
+ code="proposal_provider_transport_failed",
318
+ model=self.model,
319
+ provider="orizu",
320
+ provider_code=provider_code,
321
+ ) from error
322
+
323
+ usage = _require_usage(completion.usage)
324
+ success_event = {
325
+ "source": "skilled_proposer",
326
+ "status": "success",
327
+ "attempt": 1,
328
+ "correlation_id": correlation_id,
329
+ "provider": completion.provider,
330
+ "model": self.model,
331
+ "request_id": completion.request_id,
332
+ "latency_ms": completion.latency_ms,
333
+ "usage": usage,
334
+ "cache_state": "disabled",
335
+ }
336
+ try:
337
+ self._observability.record_success(success_event, usage)
338
+ except Exception as error:
339
+ self._observability.record_event_failure(error, correlation_id=correlation_id)
340
+ raise RuntimeError("proposal_observability_event_failed") from error
341
+ return dspy_module.LMResponse.from_text(completion.text, model=self.model, usage=usage, cache_hit=False)
342
+
343
+
344
+ def make_skilled_proposer_bridge(
345
+ *,
346
+ config: TextGepaConfig,
347
+ observability: ProposalObservability,
348
+ budget: ProposalCallBudget,
349
+ endpoint_override: str | None = None,
350
+ ssl_cert_file: str | None = None,
351
+ ) -> OrizuSkilledProposerLM:
352
+ """Create the cache-disabled typed LM passed to unmodified SkilledProposer."""
353
+ observability.bind_budget(budget)
354
+ return OrizuSkilledProposerLM(
355
+ config=config,
356
+ observability=observability,
357
+ endpoint_override=endpoint_override,
358
+ ssl_cert_file=ssl_cert_file,
359
+ )
360
+
361
+
362
+ def make_skilled_proposer_from_environment(
363
+ *,
364
+ config: TextGepaConfig,
365
+ observability: ProposalObservability,
366
+ budget: ProposalCallBudget | None = None,
367
+ endpoint_override: str | None = None,
368
+ ) -> Any | None:
369
+ """Create the opt-in proposer only for the exact selected environment value."""
370
+ if os.environ.get(_SELECTION_ENV) != _SELECTION_VALUE:
371
+ return None
372
+ from skilled_proposer import SkilledProposer
373
+
374
+ bridge = make_skilled_proposer_bridge(
375
+ config=config,
376
+ observability=observability,
377
+ budget=budget or ProposalCallBudget(),
378
+ endpoint_override=endpoint_override,
379
+ ssl_cert_file=os.environ.get("SSL_CERT_FILE"),
380
+ )
381
+ return SkilledProposer(prompt_model=bridge)
@@ -0,0 +1,55 @@
1
+ """GEPA stop conditions that preserve Orizu's iteration boundaries."""
2
+
3
+ from collections.abc import Callable
4
+
5
+
6
+ class IterationBoundaryStopper:
7
+ def __init__(self, max_iterations: int):
8
+ self.max_iterations = max_iterations
9
+
10
+ def __call__(self, state):
11
+ # GEPA's real loop starts at i=-1. Let it enter and complete the first
12
+ # iteration so this red is raised from the engine boundary, not test setup.
13
+ return state.i >= self.max_iterations - 1
14
+
15
+
16
+ class MandatoryLoggingStopper:
17
+ """Stop at GEPA's next safe boundary after a durable-log failure."""
18
+
19
+ def __init__(self, failure_flag):
20
+ self.failure_flag = failure_flag
21
+
22
+ def __call__(self, state):
23
+ return bool(self.failure_flag()) and state.i >= 0
24
+
25
+
26
+ class MaxCandidateProposalsStopper:
27
+ """Bound M1's candidate proposals at a safe GEPA boundary.
28
+
29
+ A completed iteration can skip reflection and produce no candidate. The
30
+ callback trace is therefore authoritative; rejected proposals still count.
31
+ """
32
+
33
+ def __init__(self, max_candidate_proposals: int, proposal_count: Callable[[], int]):
34
+ self.max_candidate_proposals = max_candidate_proposals
35
+ self.proposal_count = proposal_count
36
+
37
+ def __call__(self, state):
38
+ return self.proposal_count() >= self.max_candidate_proposals
39
+
40
+
41
+ class ProposalBudgetStopper:
42
+ """Stop only between GEPA iterations after an owned proposal budget trips.
43
+
44
+ A custom candidate proposer does not pass through GEPA's ``reflection_lm``
45
+ or its cost tracking. Its typed DSPy bridge instead records raw provider
46
+ usage in an Orizu-owned ledger. This stopper deliberately reads only that
47
+ ledger and never changes ``state.total_num_evals``: metric-call budgeting
48
+ remains evaluator-only.
49
+ """
50
+
51
+ def __init__(self, proposal_budget):
52
+ self.proposal_budget = proposal_budget
53
+
54
+ def __call__(self, state):
55
+ return self.proposal_budget.has_safe_boundary_stop() and state.i >= 0
@@ -0,0 +1,203 @@
1
+ """Translate official-GEPA callbacks into Orizu's established event envelope."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from typing import Any
7
+
8
+
9
+ TRUNCATION_MARKER = "…[truncated]"
10
+
11
+
12
+ def _candidate_id(value: Any) -> str | None:
13
+ if value is None:
14
+ return None
15
+ return str(value)
16
+
17
+
18
+ def _truncate(value: str, limit: int | None) -> tuple[str, bool]:
19
+ if limit is None or len(value) <= limit:
20
+ return value, False
21
+ return value[:limit] + TRUNCATION_MARKER, True
22
+
23
+
24
+ def _components(candidate: Any, limit: int | None) -> tuple[dict[str, str], dict[str, int]]:
25
+ if not isinstance(candidate, dict):
26
+ return {}, {}
27
+ result: dict[str, str] = {}
28
+ truncated: dict[str, int] = {}
29
+ for key, value in candidate.items():
30
+ if not isinstance(key, str) or not isinstance(value, str):
31
+ continue
32
+ text, did_truncate = _truncate(value, limit)
33
+ result[key] = text
34
+ if did_truncate:
35
+ truncated[f"components.{key}"] = len(value.encode("utf-8"))
36
+ return result, truncated
37
+
38
+
39
+ def _row_results(event: dict[str, Any]) -> list[dict[str, Any]]:
40
+ scores = event.get("scores_by_val_id") or event.get("scores_by_id") or {}
41
+ outputs = event.get("outputs_by_val_id") or event.get("outputs_by_id") or {}
42
+ feedbacks = event.get("feedbacks_by_val_id") or {}
43
+ errors = event.get("errors_by_val_id") or {}
44
+ if not isinstance(scores, dict):
45
+ return []
46
+ rows = []
47
+ for row_id, score in scores.items():
48
+ output = outputs.get(row_id) if isinstance(outputs, dict) else None
49
+ side_info = output if isinstance(output, dict) else {}
50
+ adapter_row_id = side_info.get("row_id")
51
+ if adapter_row_id is None and str(row_id).isdigit():
52
+ raise ValueError(
53
+ "official GEPA callback carried positional row id without adapter row identity"
54
+ )
55
+ feedback = feedbacks.get(row_id) if isinstance(feedbacks, dict) else None
56
+ error = errors.get(row_id) if isinstance(errors, dict) else None
57
+ rows.append({
58
+ "row_id": str(adapter_row_id if adapter_row_id is not None else row_id),
59
+ "score": score if isinstance(score, (int, float)) else None,
60
+ # Official GEPA's typed callback has no feedback fields. The
61
+ # adapter therefore carries them in its rollout side-info; accept
62
+ # explicit callback maps too for forward compatibility.
63
+ "feedback": feedback if feedback is not None else side_info.get("feedback"),
64
+ "error": error if error is not None else side_info.get("error"),
65
+ "output": side_info.get("output", output),
66
+ })
67
+ return rows
68
+
69
+
70
+ def translate_callback(event_name: str, event: dict[str, Any], *, run_id: str, **options: Any) -> dict[str, Any]:
71
+ """Return an Orizu event for one official callback.
72
+
73
+ ``max_payload_chars`` is deliberately characters, not bytes: the payload
74
+ disclosure retains original UTF-8 byte lengths for auditability.
75
+ """
76
+ max_chars = options.get("max_payload_chars")
77
+ if max_chars is not None and (not isinstance(max_chars, int) or max_chars <= 0):
78
+ raise ValueError("max_payload_chars must be a positive integer")
79
+
80
+ iteration = event.get("iteration")
81
+ candidate_id = _candidate_id(event.get("candidate_idx", event.get("new_candidate_idx")))
82
+ parent_ids = event.get("parent_ids")
83
+ parent_candidate_id = (
84
+ _candidate_id(parent_ids[0])
85
+ if isinstance(parent_ids, (list, tuple)) and parent_ids else None
86
+ )
87
+ candidate = (
88
+ event.get("candidate")
89
+ or event.get("new_instructions")
90
+ or event.get("seed_candidate")
91
+ or event.get("parent_candidate")
92
+ or {}
93
+ )
94
+ components, truncation = _components(candidate, max_chars)
95
+ payload: dict[str, Any] = {"components": components} if components else {}
96
+ translated_name = event_name.removeprefix("on_")
97
+ event_type = translated_name
98
+
99
+ if event_name == "on_optimization_start":
100
+ event_type = "run_started"
101
+ payload.pop("components", None)
102
+ payload.update({
103
+ "seed_candidate_text": next(iter(components.values()), None),
104
+ "seed_components": components,
105
+ "trainset_size": event.get("trainset_size"),
106
+ "valset_size": event.get("valset_size"),
107
+ })
108
+ elif event_name == "on_iteration_start":
109
+ event_type = "iteration_started"
110
+ elif event_name == "on_iteration_end":
111
+ event_type = "iteration_completed"
112
+ payload.update({
113
+ "accepted": event.get("proposal_accepted"),
114
+ "skipped_reflection": event.get("skipped_reflection", False),
115
+ })
116
+ elif event_name == "on_optimization_end":
117
+ event_type = "run_completed"
118
+ payload.update({
119
+ "best_candidate_id": _candidate_id(event.get("best_candidate_idx")),
120
+ "total_iterations": event.get("total_iterations"),
121
+ "total_metric_calls": event.get("total_metric_calls"),
122
+ })
123
+ elif event_name == "on_candidate_accepted":
124
+ event_type = "acceptance_decision_made"
125
+ payload.update({
126
+ "accepted": True,
127
+ "proceed_to_valset": True,
128
+ "parent_score_total": event.get("parent_score_total"),
129
+ "child_score_total": event.get("child_score_total", event.get("new_score")),
130
+ })
131
+ elif event_name == "on_candidate_rejected":
132
+ event_type = "acceptance_decision_made"
133
+ payload.update({
134
+ "accepted": False,
135
+ "proceed_to_valset": False,
136
+ "parent_score_total": event.get("parent_score_total", event.get("old_score")),
137
+ "child_score_total": event.get("child_score_total", event.get("new_score")),
138
+ "reason": event.get("reason"),
139
+ })
140
+ elif event_name == "on_evaluation_skipped":
141
+ event_type = "reflection_skipped"
142
+ skipped_scores = event.get("scores") or []
143
+ payload.update({"reason": event.get("reason"), "parent_score_mean": (sum(skipped_scores) / len(skipped_scores)) if skipped_scores else None})
144
+ elif event_name == "on_valset_evaluated":
145
+ is_seed = iteration == 0 and candidate_id in {"0", "seed"}
146
+ event_type = "seed_val_set_completed" if is_seed else "child_val_set_completed"
147
+ rows = _row_results(event)
148
+ payload.update({
149
+ "candidate_id": "seed" if is_seed else candidate_id,
150
+ "split": "validation",
151
+ "score_mean": event.get("average_score"),
152
+ "row_results": rows,
153
+ "is_new_best": bool(event.get("is_best_program")),
154
+ })
155
+ elif event_name == "on_proposal_end":
156
+ event_type = "reflection_completed"
157
+ raw = event.get("raw_lm_outputs")
158
+ response = next(iter(raw.values()), None) if isinstance(raw, dict) else raw
159
+ prompts = event.get("prompts")
160
+ prompt = next(iter(prompts.values()), None) if isinstance(prompts, dict) else prompts
161
+ payload.update({"prompt": prompt, "response": response, "candidate_text": next(iter(components.values()), None)})
162
+ elif event_name == "on_budget_updated":
163
+ budget_kind = options.get("budget_kind", "max_metric_calls")
164
+ budget_limit = options.get("budget_limit")
165
+ if budget_kind == "max_metric_calls":
166
+ used = event.get("metric_calls_used")
167
+ remaining = event.get("metric_calls_remaining")
168
+ elif budget_kind == "max_iterations":
169
+ used = event.get("iteration", 0)
170
+ remaining = max(0, budget_limit - used) if isinstance(budget_limit, int) else None
171
+ else:
172
+ used = event.get("num_full_ds_evals", event.get("iteration", 0))
173
+ remaining = max(0, budget_limit - used) if isinstance(budget_limit, int) else None
174
+ event_type = "optimization_progress"
175
+ payload = {
176
+ "budget_kind": budget_kind,
177
+ "used": used,
178
+ "metric_calls_used": event.get("metric_calls_used"),
179
+ "metric_calls_remaining": event.get("metric_calls_remaining"),
180
+ "limit": budget_limit,
181
+ "budget_limit": budget_limit,
182
+ "metric_call_budget": options.get("approx_metric_call_limit") if budget_kind != "max_iterations" else None,
183
+ "remaining": remaining,
184
+ }
185
+ elif event_name == "on_merge_attempted":
186
+ note = {
187
+ "eventType": "run_note", "eventLayer": "extension", "optimizerFamily": "gepa",
188
+ "payload": {"code": "unsupported_gepa_merge", "message": "unsupported GEPA merge: two-parent candidates cannot be rendered"},
189
+ }
190
+ sink = options.get("run_note_sink")
191
+ if isinstance(sink, Callable):
192
+ sink(note)
193
+ raise ValueError("unsupported GEPA merge: two-parent candidates cannot be rendered")
194
+
195
+ if truncation:
196
+ payload["payload_truncated"] = True
197
+ payload["truncation"] = {"fields": truncation}
198
+ return {
199
+ "runId": run_id, "eventType": event_type, "optimizerFamily": "gepa", "iteration": iteration,
200
+ "candidateId": "seed" if event_name == "on_valset_evaluated" and iteration == 0 and candidate_id in {"0", "seed"} else candidate_id,
201
+ "parentCandidateId": parent_candidate_id, "childCandidateId": None,
202
+ "payload": payload,
203
+ }
@@ -3,7 +3,7 @@ requires = ["setuptools>=68"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
- name = "orizu-gepa"
6
+ name = "orizu-gepa-legacy"
7
7
  version = "0.1.0"
8
8
  description = "Orizu-owned text prompt optimizer with GEPA-style reflection and mandatory live logging."
9
9
  requires-python = ">=3.10"
@@ -276,6 +276,7 @@ def main() -> None:
276
276
 
277
277
  run_metadata = {
278
278
  **metadata,
279
+ "engine": "legacy",
279
280
  "scorer_input_contract": scorer_input_contract,
280
281
  "scorer_candidate_output_field": scorer_candidate_output_field,
281
282
  "optimizer_package": "orizu-gepa-python",