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,53 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ from dataclasses import dataclass, field
5
+ from typing import Any, Generic, Protocol
6
+
7
+ from gepa.core.data_loader import DataId
8
+ from gepa.core.state import GEPAState
9
+
10
+
11
+ @dataclass
12
+ class SubsampleEvaluation:
13
+ """Result of evaluating a candidate on the subsample minibatch.
14
+
15
+ Captures all outputs from ``adapter.evaluate``:
16
+
17
+ - ``scores``: per-example numeric scores.
18
+ - ``outputs``: per-example raw outputs (e.g. the model's response text).
19
+ - ``objective_scores``: optional per-example multi-objective score dicts.
20
+ - ``trajectories``: optional per-example execution traces (captured for both
21
+ before and after evaluations).
22
+ """
23
+
24
+ scores: list[float]
25
+ outputs: list[Any] = field(default_factory=list)
26
+ objective_scores: list[dict[str, float]] | None = None
27
+ trajectories: list[Any] | None = None
28
+
29
+
30
+ @dataclass
31
+ class CandidateProposal(Generic[DataId]):
32
+ candidate: dict[str, str]
33
+ parent_program_ids: list[int]
34
+ # Optional mini-batch / subsample info
35
+ subsample_indices: list[DataId] | None = None
36
+ subsample_scores_before: list[float] | None = None
37
+ subsample_scores_after: list[float] | None = None
38
+ # Rich evaluation data (superset of scores — includes outputs, objective_scores, trajectories)
39
+ eval_before: SubsampleEvaluation | None = None
40
+ eval_after: SubsampleEvaluation | None = None
41
+ # Free-form metadata for logging/trace
42
+ tag: str = ""
43
+ metadata: dict[str, Any] = field(default_factory=dict)
44
+
45
+
46
+ class ProposeNewCandidate(Protocol[DataId]):
47
+ """
48
+ Strategy that receives the current optimizer state and proposes a new candidate or returns None.
49
+ It may compute subsample evaluations, set trace fields in state, etc.
50
+ The engine will handle acceptance and full eval unless the strategy already did those and encoded in metadata.
51
+ """
52
+
53
+ def propose(self, state: GEPAState[Any, DataId]) -> CandidateProposal | None: ...
@@ -0,0 +1,403 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ import math
5
+ import random
6
+ from collections.abc import Callable, Iterable, Sequence
7
+ from copy import deepcopy
8
+
9
+ from gepa.core.adapter import Candidate, DataInst, RolloutOutput
10
+ from gepa.core.callbacks import (
11
+ EvaluationEndEvent,
12
+ EvaluationStartEvent,
13
+ GEPACallback,
14
+ notify_callbacks,
15
+ )
16
+ from gepa.core.data_loader import DataId, DataLoader
17
+ from gepa.core.state import GEPAState, ObjectiveScores, ProgramIdx
18
+ from gepa.gepa_utils import find_dominator_programs
19
+ from gepa.logging.logger import LoggerProtocol
20
+ from gepa.proposer.base import CandidateProposal, ProposeNewCandidate
21
+
22
+ AncestorLog = tuple[int, int, int]
23
+ MergeDescription = tuple[int, int, tuple[int, ...]]
24
+ MergeAttempt = tuple[Candidate, ProgramIdx, ProgramIdx, ProgramIdx] | None
25
+
26
+
27
+ def does_triplet_have_desirable_predictors(
28
+ program_candidates: Sequence[Candidate],
29
+ ancestor: ProgramIdx,
30
+ id1: ProgramIdx,
31
+ id2: ProgramIdx,
32
+ ) -> bool:
33
+ found_predictors: list[tuple[int, int]] = []
34
+ pred_names = list(program_candidates[ancestor].keys())
35
+ for pred_idx, pred_name in enumerate(pred_names):
36
+ pred_anc = program_candidates[ancestor][pred_name]
37
+ pred_id1 = program_candidates[id1][pred_name]
38
+ pred_id2 = program_candidates[id2][pred_name]
39
+ if (pred_anc == pred_id1 or pred_anc == pred_id2) and pred_id1 != pred_id2:
40
+ same_as_ancestor_id = 1 if pred_anc == pred_id1 else 2
41
+ found_predictors.append((pred_idx, same_as_ancestor_id))
42
+
43
+ return len(found_predictors) > 0
44
+
45
+
46
+ def filter_ancestors(
47
+ i: ProgramIdx,
48
+ j: ProgramIdx,
49
+ common_ancestors: Iterable[ProgramIdx],
50
+ merges_performed: tuple[list[AncestorLog], list[MergeDescription]],
51
+ agg_scores: Sequence[float],
52
+ program_candidates: Sequence[Candidate],
53
+ ) -> list[ProgramIdx]:
54
+ filtered_ancestors: list[ProgramIdx] = []
55
+ for ancestor in common_ancestors:
56
+ if (i, j, ancestor) in merges_performed[0]:
57
+ continue
58
+
59
+ if agg_scores[ancestor] > agg_scores[i] or agg_scores[ancestor] > agg_scores[j]:
60
+ continue
61
+
62
+ if not does_triplet_have_desirable_predictors(program_candidates, ancestor, i, j):
63
+ continue
64
+
65
+ filtered_ancestors.append(ancestor)
66
+ return filtered_ancestors
67
+
68
+
69
+ def find_common_ancestor_pair(
70
+ rng: random.Random,
71
+ parent_list: Sequence[Sequence[int | None]],
72
+ program_indexes: Sequence[int],
73
+ merges_performed: tuple[list[AncestorLog], list[MergeDescription]],
74
+ agg_scores: Sequence[float],
75
+ program_candidates: Sequence[Candidate],
76
+ max_attempts: int = 10,
77
+ ) -> tuple[int, int, int] | None:
78
+ def get_ancestors(node: int, ancestors_found: set[int]) -> list[int]:
79
+ parents = parent_list[node]
80
+ for parent in parents:
81
+ if parent is not None and parent not in ancestors_found:
82
+ ancestors_found.add(parent)
83
+ get_ancestors(parent, ancestors_found)
84
+
85
+ return list(ancestors_found)
86
+
87
+ for _ in range(max_attempts):
88
+ if len(program_indexes) < 2:
89
+ return None
90
+ i, j = rng.sample(list(program_indexes), 2)
91
+ if i == j:
92
+ continue
93
+
94
+ if j < i:
95
+ i, j = j, i
96
+
97
+ ancestors_i = get_ancestors(i, set())
98
+ ancestors_j = get_ancestors(j, set())
99
+
100
+ if j in ancestors_i or i in ancestors_j:
101
+ # If one is an ancestor of the other, we cannot merge them
102
+ continue
103
+
104
+ common_ancestors = set(ancestors_i) & set(ancestors_j)
105
+ common_ancestors = filter_ancestors(i, j, common_ancestors, merges_performed, agg_scores, program_candidates)
106
+ if common_ancestors:
107
+ # Select a random common ancestor
108
+ common_ancestor = rng.choices(
109
+ list(common_ancestors),
110
+ k=1,
111
+ weights=[agg_scores[ancestor] for ancestor in common_ancestors],
112
+ )[0]
113
+ return (i, j, common_ancestor)
114
+
115
+ return None
116
+
117
+
118
+ def sample_and_attempt_merge_programs_by_common_predictors(
119
+ agg_scores: Sequence[float],
120
+ rng: random.Random,
121
+ merge_candidates: Sequence[int],
122
+ merges_performed: tuple[list[AncestorLog], list[MergeDescription]],
123
+ program_candidates: Sequence[Candidate],
124
+ parent_program_for_candidate: Sequence[Sequence[int | None]],
125
+ has_val_support_overlap: Callable[[ProgramIdx, ProgramIdx], bool] | None = None,
126
+ max_attempts: int = 10,
127
+ ) -> MergeAttempt:
128
+ if len(merge_candidates) < 2:
129
+ return None
130
+ if len(parent_program_for_candidate) < 3:
131
+ return None
132
+
133
+ for _ in range(max_attempts):
134
+ ids_to_merge = find_common_ancestor_pair(
135
+ rng,
136
+ parent_program_for_candidate,
137
+ list(merge_candidates),
138
+ merges_performed=merges_performed,
139
+ agg_scores=agg_scores,
140
+ program_candidates=program_candidates,
141
+ max_attempts=max_attempts,
142
+ )
143
+ if ids_to_merge is None:
144
+ continue
145
+ id1, id2, ancestor = ids_to_merge
146
+
147
+ if (id1, id2, ancestor) in merges_performed[0]:
148
+ continue
149
+ assert agg_scores[ancestor] <= agg_scores[id1], "Ancestor should not be better than its descendants"
150
+ assert agg_scores[ancestor] <= agg_scores[id2], "Ancestor should not be better than its descendants"
151
+ assert id1 != id2, "Cannot merge the same program"
152
+
153
+ # Now we have a common ancestor, which is outperformed by both its descendants
154
+
155
+ new_program: Candidate = deepcopy(program_candidates[ancestor])
156
+
157
+ new_prog_desc: tuple[ProgramIdx, ...] = ()
158
+
159
+ pred_names = set(program_candidates[ancestor].keys())
160
+ assert pred_names == set(program_candidates[id1].keys()) == set(program_candidates[id2].keys()), (
161
+ "Predictors should be the same across all programs"
162
+ )
163
+ for pred_name in pred_names:
164
+ pred_anc = program_candidates[ancestor][pred_name]
165
+ pred_id1 = program_candidates[id1][pred_name]
166
+ pred_id2 = program_candidates[id2][pred_name]
167
+ if (pred_anc == pred_id1 or pred_anc == pred_id2) and pred_id1 != pred_id2:
168
+ # We have a predictor that is the same as one of its ancestors, so we can update it with the other
169
+ same_as_ancestor_id = 1 if pred_anc == pred_id1 else 2
170
+ new_value_idx = id2 if same_as_ancestor_id == 1 else id1
171
+ new_program[pred_name] = program_candidates[new_value_idx][pred_name]
172
+ new_prog_desc = (*new_prog_desc, new_value_idx)
173
+ elif pred_anc != pred_id1 and pred_anc != pred_id2:
174
+ # Both predictors are different from the ancestor, and it is difficult to decide which one gives the benefits
175
+ # We randomly select one of the descendants to update the predictor
176
+ # The probability of selecting is proportional to the agg_scores of the descendants
177
+ # prog_to_get_instruction_from = id1 if (rng.random() < (agg_scores[id1] / (agg_scores[id1] + agg_scores[id2]))) else id2
178
+ prog_to_get_instruction_from = (
179
+ id1
180
+ if agg_scores[id1] > agg_scores[id2]
181
+ else (id2 if agg_scores[id2] > agg_scores[id1] else rng.choice([id1, id2]))
182
+ )
183
+ new_program[pred_name] = program_candidates[prog_to_get_instruction_from][pred_name]
184
+ new_prog_desc = (*new_prog_desc, prog_to_get_instruction_from)
185
+ elif pred_id1 == pred_id2:
186
+ # Either both predictors are the same, or both are different from the ancestor
187
+ # If both are different from the ancestor, we should use the new predictor, so selecting either one of the descendants is fine
188
+ # If both are same as the ancesor, again selecting any one of the descendants is fine
189
+ # So let's select id1
190
+ new_program[pred_name] = program_candidates[id1][pred_name]
191
+ new_prog_desc = (*new_prog_desc, id1)
192
+ else: # pragma: no cover - defensive
193
+ raise AssertionError("Unexpected case in predictor merging logic")
194
+
195
+ if (id1, id2, new_prog_desc) in merges_performed[1]:
196
+ # This triplet has already been merged, so we skip it
197
+ continue
198
+
199
+ if has_val_support_overlap and not has_val_support_overlap(id1, id2):
200
+ # Not enough overlapping validation support for candidates
201
+ continue
202
+
203
+ merges_performed[1].append((id1, id2, new_prog_desc))
204
+
205
+ return new_program, id1, id2, ancestor
206
+
207
+ return None
208
+
209
+
210
+ class MergeProposer(ProposeNewCandidate[DataId]):
211
+ """
212
+ Implements merge flow that combines compatible descendants of a common ancestor.
213
+
214
+ - Find merge candidates among Pareto front dominators
215
+ - Attempt a merge via sample_and_attempt_merge_programs_by_common_predictors
216
+ - Subsample eval on valset-driven selected indices
217
+ - Return proposal if merge's subsample score >= max(parents)
218
+ The engine handles full eval + adding to state.
219
+ """
220
+
221
+ def __init__(
222
+ self,
223
+ logger: LoggerProtocol,
224
+ valset: DataLoader[DataId, DataInst],
225
+ evaluator: Callable[
226
+ [list[DataInst], dict[str, str]],
227
+ tuple[list[RolloutOutput], list[float], Sequence[ObjectiveScores] | None],
228
+ ],
229
+ use_merge: bool,
230
+ max_merge_invocations: int,
231
+ val_overlap_floor: int = 5,
232
+ rng: random.Random | None = None,
233
+ callbacks: list[GEPACallback] | None = None,
234
+ ):
235
+ self.logger = logger
236
+ self.valset = valset
237
+ self.evaluator = evaluator
238
+ self.use_merge = use_merge
239
+ self.max_merge_invocations = max_merge_invocations
240
+ self.rng = rng if rng is not None else random.Random(0)
241
+ self.callbacks = callbacks
242
+
243
+ if val_overlap_floor <= 0:
244
+ raise ValueError("val_overlap_floor should be a positive integer")
245
+ self.val_overlap_floor = val_overlap_floor
246
+ # Internal counters matching original behavior
247
+ self.merges_due = 0
248
+ self.total_merges_tested = 0
249
+ self.merges_performed: tuple[list[AncestorLog], list[MergeDescription]] = ([], [])
250
+
251
+ # Toggle controlled by engine: set True when last iter found new program
252
+ self.last_iter_found_new_program = False
253
+
254
+ def schedule_if_needed(self) -> None:
255
+ if self.use_merge and self.total_merges_tested < self.max_merge_invocations:
256
+ self.merges_due += 1
257
+
258
+ def select_eval_subsample_for_merged_program(
259
+ self,
260
+ scores1: dict[DataId, float],
261
+ scores2: dict[DataId, float],
262
+ num_subsample_ids: int = 5,
263
+ ) -> list[DataId]:
264
+ common_ids = list(set(scores1.keys()) & set(scores2.keys()))
265
+
266
+ p1 = [idx for idx in common_ids if scores1[idx] > scores2[idx]]
267
+ p2 = [idx for idx in common_ids if scores2[idx] > scores1[idx]]
268
+ p3 = [idx for idx in common_ids if idx not in p1 and idx not in p2]
269
+
270
+ n_each = max(1, math.ceil(num_subsample_ids / 3))
271
+ selected: list[DataId] = []
272
+ for bucket in (p1, p2, p3):
273
+ if len(selected) >= num_subsample_ids:
274
+ break
275
+ available = [idx for idx in bucket if idx not in selected]
276
+ take = min(len(available), n_each, num_subsample_ids - len(selected))
277
+ if take > 0:
278
+ selected += self.rng.sample(available, k=take)
279
+
280
+ remaining = num_subsample_ids - len(selected)
281
+ if remaining > 0:
282
+ unused = [idx for idx in common_ids if idx not in selected]
283
+ if len(unused) >= remaining:
284
+ selected += self.rng.sample(unused, k=remaining)
285
+ elif common_ids:
286
+ selected += self.rng.choices(common_ids, k=remaining)
287
+
288
+ return selected[:num_subsample_ids]
289
+
290
+ def propose(self, state: GEPAState[RolloutOutput, DataId]) -> CandidateProposal[DataId] | None:
291
+ i = state.i + 1
292
+ state.full_program_trace[-1]["invoked_merge"] = True
293
+
294
+ # Only attempt when scheduled by engine and after a new program in last iteration
295
+ if not (self.use_merge and self.last_iter_found_new_program and self.merges_due > 0):
296
+ self.logger.log(f"Iteration {i}: No merge candidates scheduled")
297
+ return None
298
+
299
+ pareto_front_programs = state.get_pareto_front_mapping()
300
+
301
+ tracked_scores: Sequence[float] = getattr(
302
+ state, "per_program_tracked_scores", state.program_full_scores_val_set
303
+ )
304
+ merge_candidates = find_dominator_programs(pareto_front_programs, list(tracked_scores))
305
+
306
+ def has_val_support_overlap(id1: ProgramIdx, id2: ProgramIdx) -> bool:
307
+ common_ids = set(state.prog_candidate_val_subscores[id1].keys()) & set(
308
+ state.prog_candidate_val_subscores[id2].keys()
309
+ )
310
+ return len(common_ids) >= self.val_overlap_floor
311
+
312
+ merge_output = sample_and_attempt_merge_programs_by_common_predictors(
313
+ agg_scores=list(tracked_scores),
314
+ rng=self.rng,
315
+ merge_candidates=merge_candidates,
316
+ merges_performed=self.merges_performed,
317
+ program_candidates=state.program_candidates,
318
+ parent_program_for_candidate=state.parent_program_for_candidate,
319
+ has_val_support_overlap=has_val_support_overlap,
320
+ )
321
+
322
+ if merge_output is None:
323
+ self.logger.log(f"Iteration {i}: No merge candidates found")
324
+ return None
325
+
326
+ new_program, id1, id2, ancestor = merge_output
327
+ state.full_program_trace[-1]["merged"] = True
328
+ state.full_program_trace[-1]["merged_entities"] = (id1, id2, ancestor)
329
+ self.merges_performed[0].append((id1, id2, ancestor))
330
+ self.logger.log(f"Iteration {i}: Merged programs {id1} and {id2} via ancestor {ancestor}")
331
+
332
+ subsample_ids = self.select_eval_subsample_for_merged_program(
333
+ state.prog_candidate_val_subscores[id1],
334
+ state.prog_candidate_val_subscores[id2],
335
+ )
336
+ if not subsample_ids:
337
+ self.logger.log(
338
+ f"Iteration {i}: Skipping merge of {id1} and {id2} due to insufficient overlapping val coverage"
339
+ )
340
+ return None
341
+
342
+ assert set(subsample_ids).issubset(state.prog_candidate_val_subscores[id1].keys())
343
+ assert set(subsample_ids).issubset(state.prog_candidate_val_subscores[id2].keys())
344
+ id1_sub_scores = [state.prog_candidate_val_subscores[id1][k] for k in subsample_ids]
345
+ id2_sub_scores = [state.prog_candidate_val_subscores[id2][k] for k in subsample_ids]
346
+ state.full_program_trace[-1]["subsample_ids"] = subsample_ids
347
+
348
+ mini_devset = self.valset.fetch(subsample_ids)
349
+
350
+ # Notify evaluation start for merged candidate
351
+ notify_callbacks(
352
+ self.callbacks,
353
+ "on_evaluation_start",
354
+ EvaluationStartEvent(
355
+ iteration=i,
356
+ candidate_idx=None,
357
+ batch_size=len(mini_devset),
358
+ capture_traces=False,
359
+ parent_ids=[id1, id2],
360
+ inputs=mini_devset,
361
+ is_seed_candidate=False,
362
+ ),
363
+ )
364
+
365
+ outputs_by_id, scores_by_id, objective_by_id, actual_evals_count = state.cached_evaluate_full(
366
+ new_program, subsample_ids, self.valset.fetch, self.evaluator
367
+ )
368
+ new_sub_scores = [scores_by_id[eid] for eid in subsample_ids]
369
+ outputs = [outputs_by_id[eid] for eid in subsample_ids]
370
+
371
+ notify_callbacks(
372
+ self.callbacks,
373
+ "on_evaluation_end",
374
+ EvaluationEndEvent(
375
+ iteration=i,
376
+ candidate_idx=None,
377
+ scores=new_sub_scores,
378
+ has_trajectories=False,
379
+ parent_ids=[id1, id2],
380
+ outputs=outputs,
381
+ trajectories=None,
382
+ objective_scores=[objective_by_id[eid] for eid in subsample_ids] if objective_by_id else None,
383
+ is_seed_candidate=False,
384
+ ),
385
+ )
386
+
387
+ state.full_program_trace[-1]["id1_subsample_scores"] = id1_sub_scores
388
+ state.full_program_trace[-1]["id2_subsample_scores"] = id2_sub_scores
389
+ state.full_program_trace[-1]["new_program_subsample_scores"] = new_sub_scores
390
+
391
+ # Count evals via hook mechanism
392
+ state.increment_evals(actual_evals_count)
393
+
394
+ # Acceptance will be evaluated by engine (>= max(parents))
395
+ return CandidateProposal(
396
+ candidate=new_program,
397
+ parent_program_ids=[id1, id2],
398
+ subsample_indices=subsample_ids,
399
+ subsample_scores_before=[sum(id1_sub_scores), sum(id2_sub_scores)],
400
+ subsample_scores_after=new_sub_scores,
401
+ tag="merge",
402
+ metadata={"ancestor": ancestor},
403
+ )
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Any, ClassVar, Mapping, Protocol, runtime_checkable
6
+
7
+ from gepa.core.adapter import Trajectory
8
+ from gepa.core.state import GEPAState
9
+
10
+
11
+ @runtime_checkable
12
+ class CandidateSelector(Protocol):
13
+ def select_candidate_idx(self, state: GEPAState) -> int: ...
14
+
15
+
16
+ class ReflectionComponentSelector(Protocol):
17
+ def __call__(
18
+ self,
19
+ state: GEPAState,
20
+ trajectories: list[Trajectory],
21
+ subsample_scores: list[float],
22
+ candidate_idx: int,
23
+ candidate: dict[str, str],
24
+ ) -> list[str]: ...
25
+
26
+
27
+ class LanguageModel(Protocol):
28
+ def __call__(self, prompt: str | list[dict[str, Any]]) -> str: ...
29
+
30
+
31
+ @dataclass
32
+ class Signature:
33
+ prompt_template: ClassVar[str]
34
+ input_keys: ClassVar[list[str]]
35
+ output_keys: ClassVar[list[str]]
36
+
37
+ @classmethod
38
+ def prompt_renderer(cls, input_dict: Mapping[str, Any]) -> str | list[dict[str, Any]]:
39
+ raise NotImplementedError
40
+
41
+ @classmethod
42
+ def output_extractor(cls, lm_out: str) -> dict[str, str]:
43
+ raise NotImplementedError
44
+
45
+ @classmethod
46
+ def run(cls, lm: LanguageModel, input_dict: Mapping[str, Any]) -> dict[str, str]:
47
+ full_prompt = cls.prompt_renderer(input_dict)
48
+ lm_res = lm(full_prompt)
49
+ lm_out = lm_res.strip()
50
+ return cls.output_extractor(lm_out)
51
+
52
+ @classmethod
53
+ def run_with_metadata(
54
+ cls, lm: LanguageModel, input_dict: Mapping[str, Any]
55
+ ) -> tuple[dict[str, str], str | list[dict[str, Any]], str]:
56
+ """Like ``run()``, but also returns the rendered prompt and raw LM output.
57
+
58
+ Returns:
59
+ A tuple of (extracted_output, rendered_prompt, raw_lm_output).
60
+ """
61
+ full_prompt = cls.prompt_renderer(input_dict)
62
+ lm_res = lm(full_prompt)
63
+ lm_out = lm_res.strip()
64
+ return cls.output_extractor(lm_out), full_prompt, lm_out