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,418 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ from typing import Any
5
+
6
+ from gepa.adapters.generic_rag_adapter.vector_store_interface import VectorStoreInterface
7
+
8
+
9
+ class WeaviateVectorStore(VectorStoreInterface):
10
+ """
11
+ Weaviate implementation of the VectorStoreInterface.
12
+
13
+ Weaviate is a cloud-native, modular, real-time vector database
14
+ with powerful search capabilities including hybrid search.
15
+ Supports both Weaviate Cloud Services and self-hosted deployments.
16
+ """
17
+
18
+ def __init__(self, client, collection_name: str, embedding_function=None):
19
+ """
20
+ Initialize WeaviateVectorStore.
21
+
22
+ Args:
23
+ client: Weaviate client instance (WeaviateClient from weaviate-client)
24
+ collection_name: Name of the collection/class to use
25
+ embedding_function: Optional function to compute embeddings for queries
26
+ """
27
+ import importlib.util
28
+
29
+ if importlib.util.find_spec("weaviate") is None:
30
+ raise ImportError(
31
+ "Weaviate client is required for WeaviateVectorStore. Install with: pip install litellm weaviate-client"
32
+ )
33
+
34
+ import weaviate.classes as wvc
35
+
36
+ self.client = client
37
+ self.collection_name = collection_name
38
+ self.wvc = wvc
39
+ self.embedding_function = embedding_function
40
+
41
+ # Get the collection
42
+ try:
43
+ self.collection = self.client.collections.get(collection_name)
44
+ except Exception as e:
45
+ raise ValueError(
46
+ f"Collection '{collection_name}' not found. Please create the collection first. Error: {e!s}"
47
+ ) from e
48
+
49
+ def similarity_search(
50
+ self,
51
+ query: str,
52
+ k: int = 5,
53
+ filters: dict[str, Any] | None = None,
54
+ ) -> list[dict[str, Any]]:
55
+ """Search for documents similar to the query text using embeddings."""
56
+ if self.embedding_function is None:
57
+ raise ValueError("No embedding function provided for similarity search")
58
+
59
+ # Compute embeddings for the query
60
+ try:
61
+ query_vector = self.embedding_function(query)
62
+ if hasattr(query_vector, "tolist"):
63
+ query_vector = query_vector.tolist()
64
+ except Exception as e:
65
+ raise RuntimeError(f"Failed to compute embeddings for query: {e!s}") from e
66
+
67
+ # Use vector search with computed embeddings
68
+ return self.vector_search(query_vector, k, filters)
69
+
70
+ def vector_search(
71
+ self,
72
+ query_vector: list[float],
73
+ k: int = 5,
74
+ filters: dict[str, Any] | None = None,
75
+ ) -> list[dict[str, Any]]:
76
+ """Search using a pre-computed query vector."""
77
+ weaviate_filters = self._convert_filters(filters) if filters else None
78
+
79
+ try:
80
+ # Execute query
81
+ if weaviate_filters:
82
+ response = self.collection.query.near_vector(near_vector=query_vector, limit=k).where(weaviate_filters)
83
+ else:
84
+ response = self.collection.query.near_vector(near_vector=query_vector, limit=k)
85
+
86
+ # Handle GenerativeReturn object - access .objects attribute
87
+ if hasattr(response, "objects"):
88
+ results = response.objects
89
+ else:
90
+ results = response
91
+
92
+ return self._format_results(results)
93
+
94
+ except Exception as e:
95
+ raise RuntimeError(f"Weaviate vector search failed: {e!s}") from e
96
+
97
+ def hybrid_search(
98
+ self,
99
+ query: str,
100
+ k: int = 5,
101
+ alpha: float = 0.5,
102
+ filters: dict[str, Any] | None = None,
103
+ ) -> list[dict[str, Any]]:
104
+ """
105
+ Hybrid semantic + keyword search using Weaviate's native hybrid search.
106
+
107
+ Args:
108
+ query: Text query to search for
109
+ k: Number of documents to return
110
+ alpha: Weight for semantic vs keyword search (0.0 = pure keyword, 1.0 = pure semantic)
111
+ filters: Optional metadata filters
112
+ """
113
+ weaviate_filters = self._convert_filters(filters) if filters else None
114
+
115
+ try:
116
+ results = self.collection.query.hybrid(
117
+ query=query,
118
+ alpha=alpha,
119
+ limit=k,
120
+ where=weaviate_filters,
121
+ return_metadata=self.wvc.query.MetadataQuery(score=True, explain_score=True),
122
+ return_properties=["content", "*"],
123
+ )
124
+
125
+ return self._format_results(results)
126
+
127
+ except Exception as e:
128
+ raise RuntimeError(f"Weaviate hybrid search failed: {e!s}") from e
129
+
130
+ def get_collection_info(self) -> dict[str, Any]:
131
+ """Get metadata about the Weaviate collection."""
132
+ try:
133
+ # Get collection configuration
134
+ config = self.collection.config.get()
135
+
136
+ # Count objects in collection
137
+ count_result = self.collection.aggregate.over_all(total_count=True)
138
+ total_count = count_result.total_count
139
+
140
+ # Try to determine vector dimensions
141
+ dimension = 0
142
+ if hasattr(config, "vector_config") and config.vector_config:
143
+ # For collections with vector config
144
+ if hasattr(config.vector_config, "vector_index_config"):
145
+ vector_index = config.vector_index_config
146
+ if hasattr(vector_index, "distance"):
147
+ # This indicates vectors are configured
148
+ # Try to get dimension from a sample object
149
+ try:
150
+ sample = self.collection.query.fetch_objects(limit=1, include_vector=True)
151
+ if sample.objects and hasattr(sample.objects[0], "vector") and sample.objects[0].vector:
152
+ # Handle both named vectors and default vector
153
+ vector_data = sample.objects[0].vector
154
+ if isinstance(vector_data, dict):
155
+ # Named vectors case
156
+ for _vector_name, vector_values in vector_data.items():
157
+ if vector_values:
158
+ dimension = len(vector_values)
159
+ break
160
+ elif isinstance(vector_data, list):
161
+ # Default vector case
162
+ dimension = len(vector_data)
163
+ except Exception:
164
+ # If we can't determine dimension from sample, that's ok
165
+ pass
166
+
167
+ # Determine if hybrid search is supported
168
+ supports_hybrid = True # Weaviate generally supports hybrid search
169
+ try:
170
+ # Test if hybrid search works by doing a minimal query
171
+ self.collection.query.hybrid(query="test", limit=1)
172
+ supports_hybrid = True
173
+ except Exception:
174
+ supports_hybrid = False
175
+
176
+ return {
177
+ "name": self.collection_name,
178
+ "document_count": total_count,
179
+ "dimension": dimension,
180
+ "vector_store_type": "weaviate",
181
+ "supports_hybrid_search": supports_hybrid,
182
+ "vectorizer": getattr(config, "vectorizer_config", None),
183
+ "properties": [prop.name for prop in getattr(config, "properties", [])],
184
+ }
185
+
186
+ except Exception as e:
187
+ # Fallback info if detailed info fails
188
+ return {
189
+ "name": self.collection_name,
190
+ "document_count": 0,
191
+ "dimension": 0,
192
+ "vector_store_type": "weaviate",
193
+ "error": str(e),
194
+ }
195
+
196
+ def supports_hybrid_search(self) -> bool:
197
+ """Weaviate supports hybrid search."""
198
+ try:
199
+ # Test if hybrid search works
200
+ self.collection.query.hybrid(query="test", limit=1)
201
+ return True
202
+ except Exception:
203
+ return False
204
+
205
+ def supports_metadata_filtering(self) -> bool:
206
+ """Weaviate supports metadata filtering with where clauses."""
207
+ return True
208
+
209
+ def _convert_filters(self, filters: dict[str, Any]) -> Any:
210
+ """
211
+ Convert generic filters to Weaviate where clause format.
212
+
213
+ Generic format: {"key": "value", "key2": {"$gt": 5}}
214
+ Weaviate format uses Filter class
215
+ """
216
+ if not filters:
217
+ return None
218
+
219
+ try:
220
+ from weaviate.collections.classes.filters import Filter
221
+ except ImportError:
222
+ # Fallback if Filter class not available
223
+ return None
224
+
225
+ filter_conditions = []
226
+
227
+ for key, value in filters.items():
228
+ if isinstance(value, dict):
229
+ # Handle operator-based filters
230
+ for op, op_value in value.items():
231
+ if op == "$eq" or op == "equal":
232
+ filter_conditions.append(Filter.by_property(key).equal(op_value))
233
+ elif op == "$ne" or op == "not_equal":
234
+ filter_conditions.append(Filter.by_property(key).not_equal(op_value))
235
+ elif op == "$gt" or op == "greater_than":
236
+ filter_conditions.append(Filter.by_property(key).greater_than(op_value))
237
+ elif op == "$gte" or op == "greater_equal":
238
+ filter_conditions.append(Filter.by_property(key).greater_or_equal(op_value))
239
+ elif op == "$lt" or op == "less_than":
240
+ filter_conditions.append(Filter.by_property(key).less_than(op_value))
241
+ elif op == "$lte" or op == "less_equal":
242
+ filter_conditions.append(Filter.by_property(key).less_or_equal(op_value))
243
+ elif op == "$in" or op == "contains_any":
244
+ if isinstance(op_value, list):
245
+ filter_conditions.append(Filter.by_property(key).contains_any(op_value))
246
+ elif op == "$like" or op == "like":
247
+ filter_conditions.append(Filter.by_property(key).like(op_value))
248
+ else:
249
+ # Simple equality filter
250
+ filter_conditions.append(Filter.by_property(key).equal(value))
251
+
252
+ # Combine all conditions with AND
253
+ if len(filter_conditions) == 1:
254
+ return filter_conditions[0]
255
+ elif len(filter_conditions) > 1:
256
+ combined_filter = filter_conditions[0]
257
+ for condition in filter_conditions[1:]:
258
+ combined_filter = combined_filter & condition
259
+ return combined_filter
260
+
261
+ return None
262
+
263
+ def _format_results(self, results) -> list[dict[str, Any]]:
264
+ """Convert Weaviate results to standardized format."""
265
+ documents = []
266
+
267
+ # Handle both GenerativeReturn objects and direct lists
268
+ if hasattr(results, "objects"):
269
+ objects_list = results.objects
270
+ else:
271
+ objects_list = results
272
+
273
+ if not objects_list:
274
+ return documents
275
+
276
+ for obj in objects_list:
277
+ # Get the content - try different property names
278
+ content = ""
279
+ properties = obj.properties
280
+
281
+ # Common content field names
282
+ content_fields = ["content", "text", "document", "body", "description"]
283
+ for field in content_fields:
284
+ if field in properties:
285
+ content = properties[field]
286
+ break
287
+
288
+ # If no content field found, use all text properties
289
+ if not content:
290
+ text_properties = []
291
+ for key, value in properties.items():
292
+ if isinstance(value, str) and value.strip():
293
+ text_properties.append(f"{key}: {value}")
294
+ content = " | ".join(text_properties)
295
+
296
+ # Extract metadata (all properties except content)
297
+ metadata = {}
298
+ for key, value in properties.items():
299
+ if key not in ["content", "text", "document", "body"] or not content:
300
+ metadata[key] = value
301
+
302
+ # Add UUID as doc_id in metadata
303
+ metadata["doc_id"] = str(obj.uuid)
304
+
305
+ # Calculate similarity score from distance or use provided score
306
+ score = 0.0
307
+ if hasattr(obj.metadata, "score") and obj.metadata.score is not None:
308
+ score = float(obj.metadata.score)
309
+ elif hasattr(obj.metadata, "distance") and obj.metadata.distance is not None:
310
+ # Convert distance to similarity (assuming cosine distance)
311
+ # Weaviate cosine distance is between 0 and 2, similarity = 1 - (distance/2)
312
+ distance = float(obj.metadata.distance)
313
+ score = max(0.0, 1.0 - (distance / 2.0))
314
+
315
+ documents.append({"content": content, "metadata": metadata, "score": score})
316
+
317
+ return documents
318
+
319
+ @classmethod
320
+ def create_local(
321
+ cls,
322
+ host: str = "localhost",
323
+ port: int = 8080,
324
+ grpc_port: int = 50051,
325
+ collection_name: str = "Documents",
326
+ headers: dict[str, str] | None = None,
327
+ ) -> "WeaviateVectorStore":
328
+ """
329
+ Create a WeaviateVectorStore connected to local Weaviate instance.
330
+
331
+ Args:
332
+ host: Weaviate host
333
+ port: HTTP port
334
+ grpc_port: gRPC port
335
+ collection_name: Name of the collection
336
+ headers: Optional headers for authentication
337
+
338
+ Returns:
339
+ WeaviateVectorStore instance
340
+ """
341
+ try:
342
+ import weaviate
343
+ except ImportError as e:
344
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
345
+
346
+ client = weaviate.connect_to_local(host=host, port=port, grpc_port=grpc_port, headers=headers)
347
+
348
+ return cls(client, collection_name)
349
+
350
+ @classmethod
351
+ def create_cloud(
352
+ cls,
353
+ cluster_url: str,
354
+ auth_credentials,
355
+ collection_name: str = "Documents",
356
+ headers: dict[str, str] | None = None,
357
+ ) -> "WeaviateVectorStore":
358
+ """
359
+ Create a WeaviateVectorStore connected to Weaviate Cloud Services.
360
+
361
+ Args:
362
+ cluster_url: Weaviate cluster URL
363
+ auth_credentials: Authentication credentials (API key or other auth)
364
+ collection_name: Name of the collection
365
+ headers: Optional headers
366
+
367
+ Returns:
368
+ WeaviateVectorStore instance
369
+ """
370
+ try:
371
+ import weaviate
372
+ except ImportError as e:
373
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
374
+
375
+ client = weaviate.connect_to_weaviate_cloud(
376
+ cluster_url=cluster_url, auth_credentials=auth_credentials, headers=headers
377
+ )
378
+
379
+ return cls(client, collection_name)
380
+
381
+ @classmethod
382
+ def create_custom(
383
+ cls,
384
+ url: str,
385
+ auth_credentials=None,
386
+ collection_name: str = "Documents",
387
+ headers: dict[str, str] | None = None,
388
+ grpc_port: int | None = None,
389
+ ) -> "WeaviateVectorStore":
390
+ """
391
+ Create a WeaviateVectorStore with custom connection parameters.
392
+
393
+ Args:
394
+ url: Weaviate instance URL
395
+ auth_credentials: Authentication credentials
396
+ collection_name: Name of the collection
397
+ headers: Optional headers
398
+ grpc_port: Optional gRPC port
399
+
400
+ Returns:
401
+ WeaviateVectorStore instance
402
+ """
403
+ try:
404
+ import weaviate
405
+ except ImportError as e:
406
+ raise ImportError("Weaviate client is required. Install with: pip install litellm weaviate-client") from e
407
+
408
+ client = weaviate.connect_to_custom(
409
+ http_host=url,
410
+ http_port=443 if "https" in url else 80,
411
+ http_secure="https" in url,
412
+ grpc_port=grpc_port,
413
+ grpc_secure="https" in url,
414
+ auth_credentials=auth_credentials,
415
+ headers=headers,
416
+ )
417
+
418
+ return cls(client, collection_name)
@@ -0,0 +1,11 @@
1
+ from gepa.adapters.langchain_adapter.langchain_adapter import (
2
+ LangChainAdapter,
3
+ last_message_text,
4
+ make_reflection_lm,
5
+ )
6
+
7
+ __all__ = [
8
+ "LangChainAdapter",
9
+ "last_message_text",
10
+ "make_reflection_lm",
11
+ ]
@@ -0,0 +1,261 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import time
5
+ from collections import Counter
6
+ from collections.abc import Callable, Mapping, Sequence
7
+ from concurrent.futures import ThreadPoolExecutor, as_completed
8
+ from typing import Any
9
+
10
+ from langchain_core.language_models import BaseChatModel
11
+ from langchain_core.messages import AIMessage, HumanMessage
12
+
13
+ from gepa.core.adapter import EvaluationBatch, GEPAAdapter, ProposalFn
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ DataInst = Mapping[str, Any]
18
+ RolloutState = dict[str, Any]
19
+ RolloutFn = Callable[[dict[str, str], DataInst], RolloutState]
20
+ EvalFn = Callable[[DataInst, RolloutState], tuple[float, str]]
21
+ ReflectiveRecordFn = Callable[[DataInst, RolloutState, float, str], Mapping[str, Any]]
22
+ ReflectionLM = Callable[[str], str]
23
+
24
+
25
+ def make_reflection_lm(model: BaseChatModel | Mapping[str, Any] | str) -> ReflectionLM:
26
+ """Wrap a LangChain chat model into the `(prompt: str) -> str` callable GEPA expects.
27
+
28
+ `model` accepts either:
29
+ - a `BaseChatModel` instance,
30
+ - a `provider:model` string (passed to `init_chat_model`), or
31
+ - a kwargs mapping (passed via `init_chat_model(**model)`).
32
+ """
33
+ if not isinstance(model, BaseChatModel):
34
+ from langchain.chat_models import init_chat_model
35
+
36
+ model = init_chat_model(model) if isinstance(model, str) else init_chat_model(**dict(model))
37
+
38
+ def reflection_lm(prompt: str) -> str:
39
+ logger.debug("reflection prompt (%d chars):\n%s", len(prompt), prompt)
40
+ result = model.invoke([HumanMessage(content=prompt)])
41
+ content = result.content
42
+ if isinstance(content, list):
43
+ text = "".join(part.get("text", "") if isinstance(part, dict) else str(part) for part in content)
44
+ else:
45
+ text = str(content)
46
+ logger.debug("reflection response (%d chars):\n%s", len(text), text)
47
+ return text
48
+
49
+ return reflection_lm
50
+
51
+
52
+ def last_message_text(state: RolloutState) -> str:
53
+ """Return the text content of the last message in a rollout state.
54
+
55
+ Works for both single-turn rollouts (`{"messages": [AIMessage(...)]}`) and
56
+ agent rollouts that follow LangGraph's standard state shape.
57
+ """
58
+ messages = state.get("messages") if isinstance(state, dict) else None
59
+ if not messages:
60
+ return ""
61
+ msg = messages[-1]
62
+ content = getattr(msg, "content", msg)
63
+ if isinstance(content, list):
64
+ return "".join(part.get("text", "") if isinstance(part, dict) else str(part) for part in content)
65
+ return str(content)
66
+
67
+
68
+ def _default_reflective_record(data: DataInst, state: RolloutState, score: float, feedback: str) -> Mapping[str, Any]:
69
+ inputs = data.get("input", data)
70
+ return {
71
+ "Inputs": inputs,
72
+ "Generated Outputs": last_message_text(state),
73
+ "Feedback": feedback,
74
+ }
75
+
76
+
77
+ def _truncate(text: str, limit: int = 800) -> str:
78
+ text = text.replace("\n", " ⏎ ")
79
+ if len(text) <= limit:
80
+ return text
81
+ return text[:limit] + f"... [+{len(text) - limit} chars]"
82
+
83
+
84
+ class LangChainAdapter(GEPAAdapter):
85
+ """GEPA adapter for arbitrary LangChain rollouts.
86
+
87
+ Caller supplies:
88
+ - `rollout_fn(candidate, example) -> state dict`: any LangChain pipeline —
89
+ a single chat-model invocation, an agent built with `create_agent`, a
90
+ custom LangGraph graph, RAG, etc. Must return a state dict; for single-turn
91
+ cases return a dict with the messages key
92
+ `{"messages": messages + [AIMessage("llm response")]}`.
93
+ For agents, return the full agent state directly (e.g. `agent.invoke(...)`).
94
+ - `eval_fn(example, state) -> (score, feedback)`: scores the rollout state.
95
+ Use `last_message_text(state)` if you only need the final assistant text;
96
+ agents can inspect tool calls in `state["messages"]` directly.
97
+ Note: if `rollout_fn` raises, the adapter substitutes a stand-in state
98
+ of the form `{"messages": [AIMessage("ERROR: <type>: <msg>")], "error": e}`
99
+ and still calls `eval_fn` with it. Check `state.get("error")` to detect
100
+ rollout failures and score them appropriately (e.g. return 0.0 with a
101
+ feedback string explaining the failure to the reflection LM).
102
+ - `reflective_record_fn(example, state, score, feedback) -> mapping`
103
+ (optional): builds the per-example record passed to the reflection LM.
104
+ Defaults to `{"Inputs", "Generated Outputs", "Feedback"}` derived from
105
+ `example["input"]` and `last_message_text(state)`. Override to surface
106
+ tool-call traces, intermediate steps, or domain-specific context.
107
+ - `num_threads`: parallelism for `evaluate` (default 32).
108
+ - `custom_proposer`: optional `ProposalFn` to override GEPA's default
109
+ text-proposal behavior.
110
+ - `show_progress`: whether to render a tqdm progress bar during
111
+ `evaluate` (default True).
112
+
113
+ The candidate is a `dict[str, str]` of named text components; `rollout_fn`
114
+ decides how those components are wired into the call.
115
+ """
116
+
117
+ def __init__(
118
+ self,
119
+ rollout_fn: RolloutFn,
120
+ eval_fn: EvalFn,
121
+ num_threads: int = 32,
122
+ custom_proposer: ProposalFn | None = None,
123
+ reflective_record_fn: ReflectiveRecordFn = _default_reflective_record,
124
+ show_progress: bool = True,
125
+ ):
126
+ self.rollout_fn = rollout_fn
127
+ self.eval_fn = eval_fn
128
+ self.num_threads = num_threads
129
+ self.reflective_record_fn = reflective_record_fn
130
+ self.propose_new_texts = custom_proposer
131
+ self.show_progress = show_progress
132
+
133
+ def evaluate(
134
+ self,
135
+ batch: list[DataInst],
136
+ candidate: dict[str, str],
137
+ capture_traces: bool = False,
138
+ ) -> EvaluationBatch:
139
+ logger.info(
140
+ "evaluate: batch=%d capture_traces=%s components=%s",
141
+ len(batch),
142
+ capture_traces,
143
+ list(candidate.keys()),
144
+ )
145
+ for name, text in candidate.items():
146
+ logger.debug("candidate[%s]: %s", name, _truncate(text, limit=400))
147
+
148
+ outputs: list[Any] = [None] * len(batch)
149
+ scores: list[float] = [0.0] * len(batch)
150
+ trajectories: list[Any] | None = [None] * len(batch) if capture_traces else None
151
+
152
+ def run_one(idx: int, example: DataInst):
153
+ t0 = time.perf_counter()
154
+ error: Exception | None = None
155
+ try:
156
+ state: RolloutState = self.rollout_fn(candidate, example)
157
+ if not isinstance(state, dict):
158
+ raise TypeError(
159
+ f"rollout_fn must return a dict, got {type(state).__name__}. "
160
+ f"For single-turn chat use {{'messages': [SystemMessage(...), HumanMessage(...), AIMessage(...)]}}; "
161
+ f"for LangGraph agents return the agent state dict directly."
162
+ )
163
+ except Exception as e:
164
+ state = {"messages": [AIMessage(content=f"ERROR: {type(e).__name__}: {e}")], "error": e}
165
+ error = e
166
+ elapsed_ms = (time.perf_counter() - t0) * 1000
167
+ score, feedback = self.eval_fn(example, state)
168
+ if error is not None:
169
+ input_preview = _truncate(str(example.get("input", example)), limit=120)
170
+ logger.warning(
171
+ "example %d FAILED after %.0fms: %s: %s | input=%s",
172
+ idx,
173
+ elapsed_ms,
174
+ type(error).__name__,
175
+ error,
176
+ input_preview,
177
+ exc_info=logger.isEnabledFor(logging.DEBUG),
178
+ )
179
+ else:
180
+ logger.debug("example %d ok in %.0fms (score=%.2f)", idx, elapsed_ms, score)
181
+ return idx, state, score, feedback
182
+
183
+ start = time.perf_counter()
184
+ with ThreadPoolExecutor(max_workers=self.num_threads) as pool:
185
+ futures = [pool.submit(run_one, i, ex) for i, ex in enumerate(batch)]
186
+ iterator: Any = as_completed(futures)
187
+ if self.show_progress:
188
+ try:
189
+ from tqdm.auto import tqdm
190
+
191
+ iterator = tqdm(iterator, total=len(futures), desc="evaluate", leave=False)
192
+ except ImportError:
193
+ pass
194
+
195
+ running_correct = 0
196
+ for f in iterator:
197
+ idx, state, score, feedback = f.result()
198
+ outputs[idx] = {"state": state, "response": last_message_text(state)}
199
+ scores[idx] = score
200
+ if trajectories is not None:
201
+ trajectories[idx] = {
202
+ "data": batch[idx],
203
+ "state": state,
204
+ "score": score,
205
+ "feedback": feedback,
206
+ }
207
+ if score == 1.0:
208
+ running_correct += 1
209
+ if self.show_progress and hasattr(iterator, "set_postfix"):
210
+ iterator.set_postfix(correct=running_correct, refresh=False)
211
+ logger.debug(
212
+ " example %d: score=%.3f feedback=%s",
213
+ idx,
214
+ score,
215
+ _truncate(feedback, limit=200),
216
+ )
217
+
218
+ elapsed = time.perf_counter() - start
219
+ total = sum(scores)
220
+ mean = total / len(scores) if scores else 0.0
221
+
222
+ failure_counts: Counter[str] = Counter()
223
+ for o in outputs:
224
+ if isinstance(o, dict) and isinstance(o.get("state"), dict) and o["state"].get("error") is not None:
225
+ err_type = type(o["state"]["error"]).__name__
226
+ failure_counts[err_type] += 1
227
+ if failure_counts:
228
+ logger.warning(
229
+ "evaluate failures: %d/%d (by type: %s)",
230
+ sum(failure_counts.values()),
231
+ len(batch),
232
+ dict(failure_counts),
233
+ )
234
+
235
+ logger.info(
236
+ "evaluate done: mean=%.3f sum=%.3f n=%d in %.2fs",
237
+ mean,
238
+ total,
239
+ len(scores),
240
+ elapsed,
241
+ )
242
+ return EvaluationBatch(outputs=outputs, scores=scores, trajectories=trajectories)
243
+
244
+ def make_reflective_dataset(
245
+ self,
246
+ candidate: dict[str, str],
247
+ eval_batch: EvaluationBatch,
248
+ components_to_update: list[str],
249
+ ) -> Mapping[str, Sequence[Mapping[str, Any]]]:
250
+ records = [
251
+ self.reflective_record_fn(traj["data"], traj["state"], traj["score"], traj["feedback"])
252
+ for traj in (eval_batch.trajectories or [])
253
+ ]
254
+ if not records:
255
+ raise RuntimeError("No trajectories captured; cannot build reflective dataset.")
256
+ logger.info(
257
+ "reflective dataset: %d records for components=%s",
258
+ len(records),
259
+ components_to_update,
260
+ )
261
+ return dict.fromkeys(components_to_update, records)