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,269 @@
1
+ """Official GEPA execution wiring for the Orizu adapter and callback bridge."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Sequence
6
+ import dataclasses
7
+ import json
8
+ import random
9
+ from typing import Any
10
+
11
+ from gepa import optimize
12
+ from gepa.strategies.candidate_selector import EpsilonGreedyCandidateSelector
13
+ from orizu_gepa.optimizer import TextGepaConfig
14
+
15
+ from .callbacks import LifecycleHooks, OrizuCallback
16
+ from .preflight import validate_seed_and_scorer
17
+ from .stop_conditions import ProposalBudgetStopper
18
+
19
+
20
+ def _row_id(row: Any, index: int) -> str:
21
+ value = getattr(row, "id", row.get("id") if isinstance(row, dict) else None)
22
+ if value is None:
23
+ raise ValueError(f"GEPA dataset row at index {index} is missing its id")
24
+ return str(value)
25
+
26
+
27
+ class _RowIdentityLoader:
28
+ """Expose Orizu dataset ids to GEPA instead of its positional list ids."""
29
+
30
+ def __init__(self, rows: Sequence[Any]):
31
+ self._rows_by_id = {_row_id(row, index): row for index, row in enumerate(rows)}
32
+ if len(self._rows_by_id) != len(rows):
33
+ raise ValueError("GEPA datasets require unique DatasetRow ids")
34
+
35
+ def all_ids(self) -> list[str]:
36
+ return list(self._rows_by_id)
37
+
38
+ def fetch(self, row_ids: Sequence[str]) -> list[Any]:
39
+ return [self._rows_by_id[str(row_id)] for row_id in row_ids]
40
+
41
+ def __len__(self) -> int:
42
+ return len(self._rows_by_id)
43
+
44
+
45
+ def _with_row_identities(rows: Sequence[Any]) -> Any:
46
+ """Keep caller-supplied loaders, otherwise prevent cross-split cache aliasing."""
47
+ if hasattr(rows, "all_ids") and hasattr(rows, "fetch"):
48
+ return rows
49
+ return _RowIdentityLoader(rows)
50
+
51
+
52
+ class SeedValidationRefused(RuntimeError):
53
+ """Raised before a run is started when the scored seed has no gradient."""
54
+
55
+ def __init__(self, verdict: dict[str, Any], *, preflight_record_path: str | None = None):
56
+ self.verdict = verdict
57
+ self.preflight_record_path = preflight_record_path
58
+ message = (
59
+ f"{verdict['reason']}: preflight row evidence="
60
+ f"{json.dumps(verdict.get('row_evidence', []), ensure_ascii=False, default=str)}"
61
+ )
62
+ if preflight_record_path is not None:
63
+ message += f"; preflight record={preflight_record_path}"
64
+ super().__init__(message)
65
+
66
+
67
+ def _preflight_row_evidence(rows: list[Any], scores: list[float], outputs: list[Any]) -> list[dict[str, Any]]:
68
+ """Keep the raw scorer evidence that explains a preflight refusal."""
69
+ evidence: list[dict[str, Any]] = []
70
+ for index, score in enumerate(scores):
71
+ output = outputs[index] if index < len(outputs) and isinstance(outputs[index], dict) else {}
72
+ row = rows[index] if index < len(rows) else None
73
+ scorer_error = output.get("scorer_error")
74
+ if scorer_error is None and output.get("error_source") == "scorer":
75
+ scorer_error = output.get("error")
76
+ item = {
77
+ "row_id": output.get("row_id", getattr(row, "id", None)),
78
+ "score": score,
79
+ "scorer_output": output.get("scorer_output", output.get("scorer_response")),
80
+ "scorer_error": scorer_error,
81
+ }
82
+ if output.get("error") is not None:
83
+ item["execution_error"] = output["error"]
84
+ item["execution_error_source"] = output.get("error_source")
85
+ evidence.append(item)
86
+ return evidence
87
+
88
+
89
+ def _validate_seed_before_run(*, seed_candidate: dict[str, str], valset: list[Any], adapter: Any,
90
+ hooks: LifecycleHooks, allow_degenerate_seed: bool) -> tuple[dict[str, Any], Any, list[Any]]:
91
+ """Cheap scorer preflight; GEPA owns the single full seed validation."""
92
+ # The approved cap bounds preflight spend. With a binary scorer and a seed
93
+ # that is correct 70% of the time, all three sampled rows can still score
94
+ # zero with probability 0.3**3 = 2.7%; do not silently change that policy.
95
+ preflight_rows = valset[:min(3, len(valset))]
96
+ seed_evaluation = adapter.evaluate(preflight_rows, seed_candidate, capture_traces=True)
97
+ scores = list(seed_evaluation.scores)
98
+ verdict = validate_seed_and_scorer(
99
+ scores=scores,
100
+ row_evidence=_preflight_row_evidence(preflight_rows, scores, list(seed_evaluation.outputs)),
101
+ allow_degenerate_seed=allow_degenerate_seed,
102
+ higher_is_better=getattr(getattr(adapter, "scorer_context", None), "higher_is_better", True),
103
+ )
104
+ verdict["preflight_metric_calls"] = getattr(adapter, "metric_calls_used", seed_evaluation.num_metric_calls)
105
+ hooks.emit("seed_validated", verdict)
106
+ if not verdict["allowed"]:
107
+ raise SeedValidationRefused(verdict)
108
+ return verdict, seed_evaluation, preflight_rows
109
+
110
+
111
+ def validate_seed_before_run(*, seed_candidate: dict[str, str], valset: list[Any], adapter: Any,
112
+ hooks: LifecycleHooks, allow_degenerate_seed: bool) -> dict[str, Any]:
113
+ """Validate the seed and return the durable public preflight verdict."""
114
+ verdict, _evaluation, _rows = _validate_seed_before_run(
115
+ seed_candidate=seed_candidate,
116
+ valset=valset,
117
+ adapter=adapter,
118
+ hooks=hooks,
119
+ allow_degenerate_seed=allow_degenerate_seed,
120
+ )
121
+ return verdict
122
+
123
+
124
+ class _PreflightReusingAdapter:
125
+ """Serve GEPA's immediate seed evaluation from the completed preflight."""
126
+
127
+ def __init__(self, adapter: Any, seed_candidate: dict[str, str], rows: list[Any], evaluation: Any):
128
+ self._adapter = adapter
129
+ self._seed_candidate = seed_candidate
130
+ self._rows = rows
131
+ self._evaluation = evaluation
132
+ self._served_seed = False
133
+
134
+ def evaluate(self, batch: list[Any], candidate: dict[str, str], capture_traces: bool = False):
135
+ if (not self._served_seed and not capture_traces and candidate == self._seed_candidate
136
+ and list(batch) == self._rows):
137
+ self._served_seed = True
138
+ return self._evaluation
139
+ return self._adapter.evaluate(batch, candidate, capture_traces=capture_traces)
140
+
141
+ def __getattr__(self, name: str) -> Any:
142
+ return getattr(self._adapter, name)
143
+
144
+
145
+ def run_official_gepa(
146
+ *,
147
+ seed_candidate: dict[str, str],
148
+ trainset: list[Any],
149
+ valset: list[Any],
150
+ adapter: Any,
151
+ callback: Any,
152
+ hooks: LifecycleHooks,
153
+ max_metric_calls: int | None = None,
154
+ stop_callbacks: Sequence[Callable[[Any], bool]] = (),
155
+ allow_degenerate_seed: bool = False,
156
+ reflection_lm: Callable[[str], str] | None = None,
157
+ custom_candidate_proposer: Callable[..., dict[str, str]] | None = None,
158
+ proposal_budget: Any | None = None,
159
+ seed_already_validated: bool = False,
160
+ config: TextGepaConfig | None = None,
161
+ module_selector: str = "round_robin",
162
+ ) -> Any:
163
+ """Run GEPA after the launch-time seed check and emit named lifecycle hooks.
164
+
165
+ The seed pass is deliberately outside ``optimize``: a bad scorer/seed is
166
+ refused before an optimization run exists or any configured GEPA budget is
167
+ consumed. The actual GEPA loop remains responsible for every later
168
+ stopping boundary.
169
+ """
170
+ # Full-valset evaluations bypass GEPA's evaluation callbacks. Give the
171
+ # callback the real adapter so it can turn GEPA's positional score keys
172
+ # into the adapter's durable dataset row identities.
173
+ if isinstance(callback, OrizuCallback):
174
+ callback.evaluation_adapter = adapter
175
+ callback.validation_row_ids = [_row_id(row, index) for index, row in enumerate(valset)]
176
+
177
+ preflight_evaluation = None
178
+ preflight_rows: list[Any] = []
179
+ if not seed_already_validated:
180
+ _verdict, preflight_evaluation, preflight_rows = _validate_seed_before_run(
181
+ seed_candidate=seed_candidate,
182
+ valset=valset,
183
+ adapter=adapter,
184
+ hooks=hooks,
185
+ allow_degenerate_seed=allow_degenerate_seed,
186
+ )
187
+
188
+ # GEPA 0.1.4 reads this optional protocol attribute directly in its
189
+ # reflective proposer, even when a custom proposer owns the call. Our
190
+ # runner adapter supplies it; lightweight adapters used by the real GEPA
191
+ # boundary do not. Normalize the vendor's optional slot without replacing
192
+ # an adapter-owned proposer.
193
+ if custom_candidate_proposer is not None and not hasattr(adapter, "propose_new_texts"):
194
+ adapter.propose_new_texts = None
195
+
196
+ gepa_adapter = adapter
197
+ if custom_candidate_proposer is not None and preflight_evaluation is not None:
198
+ # A one-row low metric ceiling otherwise pays for this same seed row a
199
+ # second time inside GEPA before it reaches the custom proposal. The
200
+ # cached result is already a real evaluator result from this call's
201
+ # mandatory preflight; only the duplicate evaluator invocation is
202
+ # removed, never the separate proposal ledger.
203
+ gepa_adapter = _PreflightReusingAdapter(adapter, seed_candidate, preflight_rows, preflight_evaluation)
204
+ if custom_candidate_proposer is not None:
205
+ # GEPA refuses an adapter-owned proposer alongside its explicit custom
206
+ # proposer. The latter is the selected skilled-proposer path.
207
+ gepa_adapter.propose_new_texts = None
208
+
209
+ config = config or TextGepaConfig()
210
+ candidate_selection_strategy: Any = config.candidate_selection_strategy
211
+ # Official GEPA's string shortcut fixes epsilon at 0.1. Use its public
212
+ # selector class so the legacy --epsilon contract remains observable.
213
+ if candidate_selection_strategy == "epsilon_greedy":
214
+ candidate_selection_strategy = EpsilonGreedyCandidateSelector(
215
+ epsilon=max(0.0, min(1.0, config.epsilon)),
216
+ rng=random.Random(config.seed),
217
+ )
218
+
219
+ owned_stop_callbacks = list(stop_callbacks)
220
+ if proposal_budget is not None:
221
+ owned_stop_callbacks.append(ProposalBudgetStopper(proposal_budget))
222
+
223
+ reflection_minibatch_size = config.minibatch_size
224
+ if custom_candidate_proposer is not None and max_metric_calls is not None:
225
+ # GEPA's metric stopper is evaluated at iteration boundaries. Do not
226
+ # let its default three-row reflection batch overshoot a deliberately
227
+ # smaller evaluator-only ceiling before that boundary is observed.
228
+ reflection_minibatch_size = min(
229
+ reflection_minibatch_size,
230
+ max(1, max_metric_calls - len(valset)),
231
+ )
232
+
233
+ kwargs: dict[str, Any] = {
234
+ "seed_candidate": seed_candidate,
235
+ "trainset": trainset,
236
+ "valset": valset,
237
+ "adapter": gepa_adapter,
238
+ "callbacks": [callback],
239
+ "stop_callbacks": owned_stop_callbacks or None,
240
+ "max_metric_calls": max_metric_calls,
241
+ "candidate_selection_strategy": candidate_selection_strategy,
242
+ "skip_perfect_score": config.skip_perfect_parent_reflection,
243
+ "reflection_minibatch_size": reflection_minibatch_size,
244
+ "cache_evaluation": config.cache_evaluations,
245
+ "seed": config.seed,
246
+ "display_progress_bar": False,
247
+ "raise_on_exception": True,
248
+ "module_selector": module_selector,
249
+ }
250
+ if reflection_lm is not None:
251
+ kwargs["reflection_lm"] = reflection_lm
252
+ # The connector implements GEPA's component-aware strategy protocol;
253
+ # passing it as a bare callable would discard the selected component.
254
+ kwargs["reflection_strategy"] = reflection_lm
255
+ if custom_candidate_proposer is not None:
256
+ kwargs["custom_candidate_proposer"] = custom_candidate_proposer
257
+ kwargs["trainset"] = _with_row_identities(trainset)
258
+ kwargs["valset"] = _with_row_identities(valset)
259
+ result = optimize(**kwargs)
260
+ if custom_candidate_proposer is not None and preflight_evaluation is not None:
261
+ # GEPA's state correctly counts its seed evaluation, but this run
262
+ # served that evaluation from the already-accounted launch preflight.
263
+ # Its public metric result must consequently retain M1's convention:
264
+ # GEPA result counts exclude the one caller preflight, while the
265
+ # adapter's physical count is result + one.
266
+ total = getattr(result, "total_metric_calls", None)
267
+ if isinstance(total, int):
268
+ result = dataclasses.replace(result, total_metric_calls=max(0, total - len(preflight_rows)))
269
+ return result
@@ -0,0 +1,52 @@
1
+ """Offline reader for the ALI-1532 synced instruction-set layout."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+
7
+ class InstructionSetLoaderError(Exception):
8
+ def __init__(self, code: str):
9
+ self.code = code
10
+ super().__init__(code)
11
+
12
+
13
+ def _inside(root: Path, candidate: Path) -> bool:
14
+ try:
15
+ candidate.relative_to(root)
16
+ return True
17
+ except ValueError:
18
+ return False
19
+
20
+
21
+ def load_instruction_set(directory: str, name: str, model_config_identity: str) -> dict[str, str]:
22
+ root = (Path(directory) / name).resolve()
23
+ if not root.is_dir():
24
+ raise InstructionSetLoaderError("instruction_set_not_synced")
25
+ manifest_path = root / "manifest.json"
26
+ if not manifest_path.is_file():
27
+ raise InstructionSetLoaderError("instruction_set_manifest_missing")
28
+ try:
29
+ manifest = json.loads(manifest_path.read_text())
30
+ except (OSError, json.JSONDecodeError) as error:
31
+ raise InstructionSetLoaderError("instruction_set_manifest_missing") from error
32
+ if manifest.get("manifestVersion") != 1:
33
+ raise InstructionSetLoaderError("instruction_set_manifest_version_unsupported")
34
+ if manifest.get("filteredTo") and model_config_identity not in manifest["filteredTo"]:
35
+ raise InstructionSetLoaderError("instruction_set_profile_not_synced")
36
+ production = next((profile.get("production") for profile in manifest.get("profiles", []) if profile.get("modelConfigIdentity") == model_config_identity), None)
37
+ material = production or manifest.get("default", {})
38
+ values: dict[str, str] = {}
39
+ for key in manifest.get("shape", []):
40
+ if key in material.get("pinnedComponents", {}):
41
+ raise InstructionSetLoaderError("instruction_set_component_unavailable")
42
+ relative = material.get("files", {}).get(key)
43
+ if not relative:
44
+ raise InstructionSetLoaderError("instruction_set_profile_key_missing")
45
+ path = (root / relative).resolve()
46
+ if not _inside(root, path):
47
+ raise InstructionSetLoaderError("instruction_set_path_unsafe")
48
+ try:
49
+ values[key] = path.read_text()
50
+ except OSError as error:
51
+ raise InstructionSetLoaderError("instruction_set_component_unreadable") from error
52
+ return values
@@ -0,0 +1,64 @@
1
+ """Launch-time safety checks performed before an optimization run exists."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from typing import Any
7
+
8
+
9
+ def validate_seed_and_scorer(
10
+ *,
11
+ scores: list[float],
12
+ row_evidence: list[dict[str, Any]] | None = None,
13
+ allow_degenerate_seed: bool,
14
+ higher_is_better: bool = True,
15
+ ) -> dict[str, Any]:
16
+ """Classify a sampled seed without treating a transient row failure as global.
17
+
18
+ A row that returns a score, including the worst score, proves the runner
19
+ and scorer pipeline executed. Only a sample containing *no* such row is
20
+ an execution refusal. Successful worst-score rows remain the separate,
21
+ deliberately bypassable ``degenerate_seed`` condition.
22
+ """
23
+ evidence = list(row_evidence or [])
24
+ successful_scores: list[float] = []
25
+ failures: dict[str, list[str | None]] = {}
26
+ for index, score in enumerate(scores):
27
+ row = evidence[index] if index < len(evidence) else {}
28
+ if row.get("scorer_error"):
29
+ reason = "scorer_execution_failed"
30
+ elif row.get("execution_error"):
31
+ source = row.get("execution_error_source")
32
+ reason = f"{source}_execution_failed" if source in {"candidate", "scorer"} else "runner_execution_failed"
33
+ else:
34
+ successful_scores.append(score)
35
+ continue
36
+ failures.setdefault(reason, []).append(row.get("row_id"))
37
+
38
+ warnings = [
39
+ {"reason": reason, "row_ids": row_ids}
40
+ for reason, row_ids in failures.items()
41
+ ]
42
+ if failures and not successful_scores and not allow_degenerate_seed:
43
+ # Every sampled row failed before yielding a usable score. Preserve a
44
+ # precise source when the failure mode is uniform, otherwise name the
45
+ # shared runner pipeline rather than pretending one source won.
46
+ reason = next(iter(failures)) if len(failures) == 1 else "runner_execution_failed"
47
+ return {"allowed": False, "reason": reason, "row_evidence": evidence}
48
+
49
+ worst_bound = all(math.isclose(score, 0.0, abs_tol=1e-9) for score in successful_scores)
50
+ # The adapter normalizes lower-is-better scores into GEPA's higher-is-
51
+ # better orientation. Legacy still refuses a uniform raw 0.0 lower-bound
52
+ # (normalized 1.0): it is a perfect seed or a silent contract mismatch,
53
+ # neither of which gives reflection a useful gradient.
54
+ lower_perfect_bound = not higher_is_better and all(
55
+ math.isclose(score, 1.0, abs_tol=1e-9) for score in successful_scores
56
+ )
57
+ degenerate = bool(successful_scores) and (worst_bound or lower_perfect_bound)
58
+ if degenerate and not allow_degenerate_seed:
59
+ verdict: dict[str, Any] = {"allowed": False, "reason": "degenerate_seed", "row_evidence": evidence}
60
+ else:
61
+ verdict = {"allowed": True, "reason": None, "row_evidence": evidence}
62
+ if warnings:
63
+ verdict["warnings"] = warnings
64
+ return verdict
@@ -0,0 +1,186 @@
1
+ """GEPA reflection callable delegated to Orizu's existing provider layer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from dataclasses import replace
7
+ import json
8
+ from typing import Any
9
+
10
+ from orizu_gepa.optimizer import DEFAULT_REFLECTION_PROMPT_TEMPLATE, build_reflection_prompt
11
+ from orizu_gepa.reflection import reflect_with_provider
12
+
13
+
14
+ def provider_reflection_lm(parent_text: str, parent_results: list[Any], config: Any) -> str:
15
+ """Run the frozen provider layer and return its raw response.
16
+
17
+ ``reflect_with_provider`` owns retries, HTTP timeouts, token accounting and
18
+ candidate extraction. The connector intentionally does not recreate any
19
+ of that transport policy.
20
+ """
21
+ result = reflect_with_provider(parent_text, parent_results, config)
22
+ return result.response
23
+
24
+
25
+ class GepaReflectionLM:
26
+ """Reflection bridge that preserves provider failures before GEPA isolates them.
27
+
28
+ GEPA intentionally catches reflection failures per proposal. That keeps an
29
+ optimization alive, but means the connector is the final durable boundary
30
+ for the actual exception. This wrapper records it *before* re-raising to
31
+ GEPA's safe helper and exposes provider-measured token usage in GEPA's
32
+ ``TrackingLM``-shaped fields.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ *,
38
+ context_supplier: Callable[[], tuple[str | dict[str, str], list[Any]]],
39
+ config: Any,
40
+ failure_reporter: Callable[..., None] | None,
41
+ success_reporter: Callable[[str], None] | None,
42
+ ) -> None:
43
+ self._context_supplier = context_supplier
44
+ self._config = config
45
+ self._failure_reporter = failure_reporter
46
+ self._success_reporter = success_reporter
47
+ self._total_tokens_in = 0
48
+ self._total_tokens_out = 0
49
+ self._total_tokens = 0
50
+
51
+ @property
52
+ def total_cost(self) -> float:
53
+ return 0.0
54
+
55
+ @property
56
+ def total_tokens_in(self) -> int:
57
+ return self._total_tokens_in
58
+
59
+ @property
60
+ def total_tokens_out(self) -> int:
61
+ return self._total_tokens_out
62
+
63
+ @property
64
+ def total_tokens(self) -> int:
65
+ return self._total_tokens
66
+
67
+ def _account_usage(self, usage: Any) -> None:
68
+ if not isinstance(usage, dict):
69
+ raise RuntimeError("ALI_1505_PROVIDER_USAGE_MISSING: reflection transport returned no provider usage")
70
+ try:
71
+ input_tokens = int(usage["input_tokens"])
72
+ output_tokens = int(usage["output_tokens"])
73
+ total_tokens = int(usage["total_tokens"])
74
+ except (KeyError, TypeError, ValueError) as error:
75
+ raise RuntimeError("ALI_1505_PROVIDER_USAGE_INVALID: reflection transport returned invalid provider usage") from error
76
+ if min(input_tokens, output_tokens, total_tokens) < 0:
77
+ raise RuntimeError("ALI_1505_PROVIDER_USAGE_INVALID: reflection transport returned negative provider usage")
78
+ self._total_tokens_in += input_tokens
79
+ self._total_tokens_out += output_tokens
80
+ self._total_tokens += total_tokens
81
+
82
+ def __call__(self, gepa_prompt: str) -> str:
83
+ parent_candidate, parent_results = self._context_supplier()
84
+ parent_text = (
85
+ json.dumps(parent_candidate, sort_keys=True, separators=(",", ":"))
86
+ if isinstance(parent_candidate, dict) and len(parent_candidate) > 1
87
+ else next(iter(parent_candidate.values()))
88
+ if isinstance(parent_candidate, dict)
89
+ else parent_candidate
90
+ )
91
+ try:
92
+ # Prompt validation is part of the provider attempt. Keep it
93
+ # inside this boundary so GEPA cannot silently swallow its error.
94
+ provider_prompt = build_reflection_prompt(parent_text, parent_results, self._config)
95
+ result = reflect_with_provider(parent_text, parent_results, self._config)
96
+ response = result.response
97
+ provider_prompt = getattr(result, "prompt", provider_prompt)
98
+ self._account_usage(getattr(result, "usage", None))
99
+ except Exception as error:
100
+ billable_usage = getattr(error, "usage", None)
101
+ if billable_usage is not None:
102
+ self._account_usage(billable_usage)
103
+ if self._failure_reporter is not None:
104
+ self._failure_reporter(
105
+ error=error,
106
+ gepa_prompt=gepa_prompt,
107
+ parent_text=parent_text,
108
+ parent_results=parent_results,
109
+ )
110
+ raise
111
+ if self._success_reporter is not None:
112
+ self._success_reporter(str(provider_prompt))
113
+ return response
114
+
115
+ def reflect(
116
+ self,
117
+ candidate: dict[str, str],
118
+ reflective_dataset: Any,
119
+ components_to_update: list[str],
120
+ ) -> tuple[Any, "GepaReflectionLM"]:
121
+ """Implement GEPA's component-aware ReflectionLM protocol.
122
+
123
+ The callable protocol has no selected-component information. GEPA's
124
+ newer protocol does, so tuples must use it rather than reverse-engineer
125
+ a key from a rendered vendor prompt.
126
+ """
127
+ from gepa.proposer.reflective_mutation.reflection_lm import ReflectionProposal
128
+
129
+ _, parent_results = self._context_supplier()
130
+ full_candidate = candidate
131
+ proposal = ReflectionProposal(new_texts={}, prompts={}, raw_lm_outputs={})
132
+ for component in components_to_update:
133
+ if component not in candidate:
134
+ continue
135
+ parent_text = candidate[component]
136
+ others = {key: value for key, value in full_candidate.items() if key != component}
137
+ config = self._config
138
+ if others:
139
+ template = config.reflection_prompt_template or DEFAULT_REFLECTION_PROMPT_TEMPLATE
140
+ config = replace(
141
+ config,
142
+ reflection_prompt_template=(
143
+ f"{template}\n\nOther instruction-set components (read-only): "
144
+ f"{json.dumps(others, sort_keys=True, ensure_ascii=False)}"
145
+ ),
146
+ )
147
+ provider_prompt = ""
148
+ try:
149
+ provider_prompt = build_reflection_prompt(parent_text, parent_results, config)
150
+ result = reflect_with_provider(parent_text, parent_results, config)
151
+ self._account_usage(getattr(result, "usage", None))
152
+ except Exception as error:
153
+ billable_usage = getattr(error, "usage", None)
154
+ if billable_usage is not None:
155
+ self._account_usage(billable_usage)
156
+ if self._failure_reporter is not None:
157
+ self._failure_reporter(error=error, gepa_prompt=provider_prompt, parent_text=parent_text, parent_results=parent_results)
158
+ raise
159
+ proposal.new_texts[component] = result.response
160
+ proposal.prompts[component] = getattr(result, "prompt", provider_prompt)
161
+ proposal.raw_lm_outputs[component] = result.response
162
+ if self._success_reporter is not None:
163
+ self._success_reporter(str(proposal.prompts[component]))
164
+ return proposal, self
165
+
166
+
167
+ def make_gepa_reflection_lm(
168
+ *,
169
+ context_supplier: Callable[[], tuple[str | dict[str, str], list[Any]]],
170
+ config: Any,
171
+ failure_reporter: Callable[..., None] | None = None,
172
+ success_reporter: Callable[[str], None] | None = None,
173
+ ) -> GepaReflectionLM:
174
+ """Adapt GEPA's ``Callable[[rendered_prompt], str]`` contract.
175
+
176
+ GEPA owns its rendered prompt. The frozen provider layer owns the
177
+ production prompt and retry policy. ``context_supplier`` is read at each
178
+ invocation, after GEPA's selected-parent minibatch evaluation, so a later
179
+ proposal cannot accidentally reflect on the seed's rows.
180
+ """
181
+ return GepaReflectionLM(
182
+ context_supplier=context_supplier,
183
+ config=config,
184
+ failure_reporter=failure_reporter,
185
+ success_reporter=success_reporter,
186
+ )