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,551 @@
1
+ # Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
2
+ # https://github.com/gepa-ai/gepa
3
+
4
+ """Callback protocol for GEPA optimization instrumentation.
5
+
6
+ This module provides a callback system for observing GEPA optimization runs.
7
+ Callbacks are synchronous, observational (cannot modify state), and receive
8
+ full GEPAState access for maximum flexibility.
9
+
10
+ Each callback receives a single event TypedDict containing all parameters.
11
+ This allows easy extension via NotRequired fields without breaking changes.
12
+
13
+ Example usage:
14
+
15
+ class MyCallback:
16
+ def on_optimization_start(self, event: OptimizationStartEvent) -> None:
17
+ print(f"Starting optimization with {event['trainset_size']} training examples")
18
+
19
+ def on_iteration_end(self, event: IterationEndEvent) -> None:
20
+ status = 'accepted' if event['proposal_accepted'] else 'rejected'
21
+ print(f"Iteration {event['iteration']}: {status}")
22
+
23
+ result = optimize(
24
+ seed_candidate={"instructions": "..."},
25
+ trainset=data,
26
+ callbacks=[MyCallback()],
27
+ ...
28
+ )
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import logging
34
+ from collections.abc import Sequence
35
+ from typing import TYPE_CHECKING, Any, Protocol, TypedDict, runtime_checkable
36
+
37
+ if TYPE_CHECKING:
38
+ from gepa.core.data_loader import DataLoader
39
+ from gepa.core.state import GEPAState, ProgramIdx
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+
44
+ # =============================================================================
45
+ # Event TypedDicts
46
+ # =============================================================================
47
+ # Each callback receives a single event object containing all parameters.
48
+ # Use NotRequired for optional fields when extending in the future.
49
+
50
+
51
+ class OptimizationStartEvent(TypedDict):
52
+ """Event for on_optimization_start callback."""
53
+
54
+ seed_candidate: dict[str, str]
55
+ trainset_size: int
56
+ valset_size: int
57
+ config: dict[str, Any]
58
+
59
+
60
+ class OptimizationEndEvent(TypedDict):
61
+ """Event for on_optimization_end callback."""
62
+
63
+ best_candidate_idx: int
64
+ total_iterations: int
65
+ total_metric_calls: int
66
+ final_state: GEPAState
67
+
68
+
69
+ class IterationStartEvent(TypedDict):
70
+ """Event for on_iteration_start callback."""
71
+
72
+ iteration: int
73
+ state: GEPAState
74
+ trainset_loader: DataLoader
75
+
76
+
77
+ class IterationEndEvent(TypedDict):
78
+ """Event for on_iteration_end callback."""
79
+
80
+ iteration: int
81
+ state: GEPAState
82
+ proposal_accepted: bool
83
+
84
+
85
+ class CandidateSelectedEvent(TypedDict):
86
+ """Event for on_candidate_selected callback."""
87
+
88
+ iteration: int
89
+ candidate_idx: int
90
+ candidate: dict[str, str]
91
+ score: float
92
+
93
+
94
+ class MinibatchSampledEvent(TypedDict):
95
+ """Event for on_minibatch_sampled callback."""
96
+
97
+ iteration: int
98
+ minibatch_ids: list[Any]
99
+ trainset_size: int
100
+
101
+
102
+ class EvaluationStartEvent(TypedDict):
103
+ """Event for on_evaluation_start callback."""
104
+
105
+ iteration: int
106
+ candidate_idx: int | None
107
+ batch_size: int
108
+ capture_traces: bool
109
+ parent_ids: Sequence[ProgramIdx]
110
+ inputs: list[Any]
111
+ is_seed_candidate: bool
112
+
113
+
114
+ class EvaluationEndEvent(TypedDict):
115
+ """Event for on_evaluation_end callback."""
116
+
117
+ iteration: int
118
+ candidate_idx: int | None
119
+ scores: list[float]
120
+ has_trajectories: bool
121
+ parent_ids: Sequence[ProgramIdx]
122
+ outputs: list[Any]
123
+ trajectories: list[Any] | None
124
+ objective_scores: list[dict[str, float]] | None
125
+ is_seed_candidate: bool
126
+
127
+
128
+ class EvaluationSkippedEvent(TypedDict):
129
+ """Event for on_evaluation_skipped callback."""
130
+
131
+ iteration: int
132
+ candidate_idx: int
133
+ reason: str
134
+ scores: list[float] | None
135
+ is_seed_candidate: bool
136
+
137
+
138
+ class ReflectiveDatasetBuiltEvent(TypedDict):
139
+ """Event for on_reflective_dataset_built callback."""
140
+
141
+ iteration: int
142
+ candidate_idx: int
143
+ components: list[str]
144
+ dataset: dict[str, list[dict[str, Any]]]
145
+
146
+
147
+ class ProposalStartEvent(TypedDict):
148
+ """Event for on_proposal_start callback."""
149
+
150
+ iteration: int
151
+ parent_candidate: dict[str, str]
152
+ components: list[str]
153
+ reflective_dataset: dict[str, list[dict[str, Any]]]
154
+
155
+
156
+ class ProposalEndEvent(TypedDict):
157
+ """Event for on_proposal_end callback."""
158
+
159
+ iteration: int
160
+ new_instructions: dict[str, str]
161
+ prompts: dict[str, str | list[dict[str, Any]]]
162
+ """Per-component prompts sent to the reflection LM (component name → rendered prompt)."""
163
+ raw_lm_outputs: dict[str, str]
164
+ """Per-component raw LM outputs before extraction (component name → raw text)."""
165
+
166
+
167
+ class CandidateAcceptedEvent(TypedDict):
168
+ """Event for on_candidate_accepted callback."""
169
+
170
+ iteration: int
171
+ new_candidate_idx: int
172
+ new_score: float
173
+ parent_ids: Sequence[ProgramIdx]
174
+
175
+
176
+ class CandidateRejectedEvent(TypedDict):
177
+ """Event for on_candidate_rejected callback."""
178
+
179
+ iteration: int
180
+ old_score: float
181
+ new_score: float
182
+ reason: str
183
+
184
+
185
+ class MergeAttemptedEvent(TypedDict):
186
+ """Event for on_merge_attempted callback."""
187
+
188
+ iteration: int
189
+ parent_ids: Sequence[ProgramIdx]
190
+ merged_candidate: dict[str, str]
191
+
192
+
193
+ class MergeAcceptedEvent(TypedDict):
194
+ """Event for on_merge_accepted callback."""
195
+
196
+ iteration: int
197
+ new_candidate_idx: int
198
+ parent_ids: Sequence[ProgramIdx]
199
+
200
+
201
+ class MergeRejectedEvent(TypedDict):
202
+ """Event for on_merge_rejected callback."""
203
+
204
+ iteration: int
205
+ parent_ids: Sequence[ProgramIdx]
206
+ reason: str
207
+
208
+
209
+ class ParetoFrontUpdatedEvent(TypedDict):
210
+ """Event for on_pareto_front_updated callback."""
211
+
212
+ iteration: int
213
+ new_front: list[int]
214
+ displaced_candidates: list[int]
215
+
216
+
217
+ class ValsetEvaluatedEvent(TypedDict):
218
+ """Event for on_valset_evaluated callback."""
219
+
220
+ iteration: int
221
+ candidate_idx: int
222
+ candidate: dict[str, str]
223
+ scores_by_val_id: dict[Any, float]
224
+ average_score: float
225
+ num_examples_evaluated: int
226
+ total_valset_size: int
227
+ parent_ids: Sequence[ProgramIdx]
228
+ is_best_program: bool
229
+ outputs_by_val_id: dict[Any, Any] | None
230
+
231
+
232
+ class StateSavedEvent(TypedDict):
233
+ """Event for on_state_saved callback."""
234
+
235
+ iteration: int
236
+ run_dir: str | None
237
+
238
+
239
+ class BudgetUpdatedEvent(TypedDict):
240
+ """Event for on_budget_updated callback."""
241
+
242
+ iteration: int
243
+ metric_calls_used: int
244
+ metric_calls_delta: int
245
+ metric_calls_remaining: int | None
246
+
247
+
248
+ class ErrorEvent(TypedDict):
249
+ """Event for on_error callback."""
250
+
251
+ iteration: int
252
+ exception: Exception
253
+ will_continue: bool
254
+
255
+
256
+ @runtime_checkable
257
+ class GEPACallback(Protocol):
258
+ """Protocol for GEPA optimization callbacks.
259
+
260
+ All methods are optional - implement only those you need.
261
+ Callbacks are called synchronously and should not modify the state.
262
+ """
263
+
264
+ # =========================================================================
265
+ # Optimization Lifecycle
266
+ # =========================================================================
267
+
268
+ def on_optimization_start(self, event: OptimizationStartEvent) -> None:
269
+ """Called when optimization begins."""
270
+ ...
271
+
272
+ def on_optimization_end(self, event: OptimizationEndEvent) -> None:
273
+ """Called when optimization completes."""
274
+ ...
275
+
276
+ # =========================================================================
277
+ # Iteration Lifecycle
278
+ # =========================================================================
279
+
280
+ def on_iteration_start(self, event: IterationStartEvent) -> None:
281
+ """Called at the start of each iteration."""
282
+ ...
283
+
284
+ def on_iteration_end(self, event: IterationEndEvent) -> None:
285
+ """Called at the end of each iteration."""
286
+ ...
287
+
288
+ # =========================================================================
289
+ # Candidate Selection and Sampling
290
+ # =========================================================================
291
+
292
+ def on_candidate_selected(self, event: CandidateSelectedEvent) -> None:
293
+ """Called when a candidate is selected for mutation."""
294
+ ...
295
+
296
+ def on_minibatch_sampled(self, event: MinibatchSampledEvent) -> None:
297
+ """Called when a training minibatch is sampled."""
298
+ ...
299
+
300
+ # =========================================================================
301
+ # Evaluation Events
302
+ # =========================================================================
303
+
304
+ def on_evaluation_start(self, event: EvaluationStartEvent) -> None:
305
+ """Called before evaluating a candidate."""
306
+ ...
307
+
308
+ def on_evaluation_end(self, event: EvaluationEndEvent) -> None:
309
+ """Called after evaluating a candidate."""
310
+ ...
311
+
312
+ def on_evaluation_skipped(self, event: EvaluationSkippedEvent) -> None:
313
+ """Called when an evaluation is skipped or its results are not used."""
314
+ ...
315
+
316
+ def on_valset_evaluated(self, event: ValsetEvaluatedEvent) -> None:
317
+ """Called after a candidate is evaluated on the validation set."""
318
+ ...
319
+
320
+ # =========================================================================
321
+ # Reflection Events
322
+ # =========================================================================
323
+
324
+ def on_reflective_dataset_built(self, event: ReflectiveDatasetBuiltEvent) -> None:
325
+ """Called after building the reflective dataset."""
326
+ ...
327
+
328
+ def on_proposal_start(self, event: ProposalStartEvent) -> None:
329
+ """Called before proposing new instructions."""
330
+ ...
331
+
332
+ def on_proposal_end(self, event: ProposalEndEvent) -> None:
333
+ """Called after proposing new instructions."""
334
+ ...
335
+
336
+ # =========================================================================
337
+ # Acceptance/Rejection Events
338
+ # =========================================================================
339
+
340
+ def on_candidate_accepted(self, event: CandidateAcceptedEvent) -> None:
341
+ """Called when a new candidate is accepted."""
342
+ ...
343
+
344
+ def on_candidate_rejected(self, event: CandidateRejectedEvent) -> None:
345
+ """Called when a candidate is rejected."""
346
+ ...
347
+
348
+ # =========================================================================
349
+ # Merge Events
350
+ # =========================================================================
351
+
352
+ def on_merge_attempted(self, event: MergeAttemptedEvent) -> None:
353
+ """Called when a merge is attempted."""
354
+ ...
355
+
356
+ def on_merge_accepted(self, event: MergeAcceptedEvent) -> None:
357
+ """Called when a merge is accepted."""
358
+ ...
359
+
360
+ def on_merge_rejected(self, event: MergeRejectedEvent) -> None:
361
+ """Called when a merge is rejected."""
362
+ ...
363
+
364
+ # =========================================================================
365
+ # State Events
366
+ # =========================================================================
367
+
368
+ def on_pareto_front_updated(self, event: ParetoFrontUpdatedEvent) -> None:
369
+ """Called when the Pareto front is updated."""
370
+ ...
371
+
372
+ def on_state_saved(self, event: StateSavedEvent) -> None:
373
+ """Called after state is saved to disk."""
374
+ ...
375
+
376
+ # =========================================================================
377
+ # Budget Tracking
378
+ # =========================================================================
379
+
380
+ def on_budget_updated(self, event: BudgetUpdatedEvent) -> None:
381
+ """Called when the evaluation budget is updated."""
382
+ ...
383
+
384
+ # =========================================================================
385
+ # Error Handling
386
+ # =========================================================================
387
+
388
+ def on_error(self, event: ErrorEvent) -> None:
389
+ """Called when an error occurs during optimization."""
390
+ ...
391
+
392
+
393
+ class CompositeCallback:
394
+ """A callback that delegates to multiple child callbacks.
395
+
396
+ This allows registering multiple callbacks and having them all
397
+ receive events.
398
+
399
+ Example:
400
+ composite = CompositeCallback([callback1, callback2])
401
+ optimize(..., callbacks=[composite])
402
+ """
403
+
404
+ def __init__(self, callbacks: list[Any] | None = None):
405
+ """Initialize with a list of callbacks.
406
+
407
+ Args:
408
+ callbacks: List of callback objects. Each should implement
409
+ some or all of the GEPACallback methods.
410
+ """
411
+ self._callbacks: list[Any] = []
412
+ # Cache: method_name -> list of (callback, bound_method) tuples
413
+ self._method_cache: dict[str, list[tuple[Any, Any]]] = {}
414
+ if callbacks:
415
+ for cb in callbacks:
416
+ self.add(cb)
417
+
418
+ @property
419
+ def callbacks(self) -> list[Any]:
420
+ """Return the list of registered callbacks."""
421
+ return self._callbacks
422
+
423
+ def add(self, callback: Any) -> None:
424
+ """Add a callback to the composite.
425
+
426
+ Args:
427
+ callback: A callback object to add.
428
+ """
429
+ self._callbacks.append(callback)
430
+ # Update cache for all known method names
431
+ for method_name in self._method_cache:
432
+ method = getattr(callback, method_name, None)
433
+ if method is not None:
434
+ self._method_cache[method_name].append((callback, method))
435
+
436
+ def _notify(self, method_name: str, event: Any) -> None:
437
+ """Notify all callbacks of an event.
438
+
439
+ Args:
440
+ method_name: Name of the callback method to invoke.
441
+ event: The event TypedDict to pass to the callback method.
442
+ """
443
+ # Build cache on first access for this method_name
444
+ if method_name not in self._method_cache:
445
+ self._method_cache[method_name] = []
446
+ for callback in self._callbacks:
447
+ method = getattr(callback, method_name, None)
448
+ if method is not None:
449
+ self._method_cache[method_name].append((callback, method))
450
+
451
+ # Use cached methods
452
+ for callback, method in self._method_cache[method_name]:
453
+ try:
454
+ method(event)
455
+ except Exception as e:
456
+ logger.warning(f"Callback {callback} failed on {method_name}: {e}")
457
+
458
+ # Delegate all callback methods
459
+
460
+ def on_optimization_start(self, event: OptimizationStartEvent) -> None:
461
+ self._notify("on_optimization_start", event)
462
+
463
+ def on_optimization_end(self, event: OptimizationEndEvent) -> None:
464
+ self._notify("on_optimization_end", event)
465
+
466
+ def on_iteration_start(self, event: IterationStartEvent) -> None:
467
+ self._notify("on_iteration_start", event)
468
+
469
+ def on_iteration_end(self, event: IterationEndEvent) -> None:
470
+ self._notify("on_iteration_end", event)
471
+
472
+ def on_candidate_selected(self, event: CandidateSelectedEvent) -> None:
473
+ self._notify("on_candidate_selected", event)
474
+
475
+ def on_minibatch_sampled(self, event: MinibatchSampledEvent) -> None:
476
+ self._notify("on_minibatch_sampled", event)
477
+
478
+ def on_evaluation_start(self, event: EvaluationStartEvent) -> None:
479
+ self._notify("on_evaluation_start", event)
480
+
481
+ def on_evaluation_end(self, event: EvaluationEndEvent) -> None:
482
+ self._notify("on_evaluation_end", event)
483
+
484
+ def on_evaluation_skipped(self, event: EvaluationSkippedEvent) -> None:
485
+ self._notify("on_evaluation_skipped", event)
486
+
487
+ def on_valset_evaluated(self, event: ValsetEvaluatedEvent) -> None:
488
+ self._notify("on_valset_evaluated", event)
489
+
490
+ def on_reflective_dataset_built(self, event: ReflectiveDatasetBuiltEvent) -> None:
491
+ self._notify("on_reflective_dataset_built", event)
492
+
493
+ def on_proposal_start(self, event: ProposalStartEvent) -> None:
494
+ self._notify("on_proposal_start", event)
495
+
496
+ def on_proposal_end(self, event: ProposalEndEvent) -> None:
497
+ self._notify("on_proposal_end", event)
498
+
499
+ def on_candidate_accepted(self, event: CandidateAcceptedEvent) -> None:
500
+ self._notify("on_candidate_accepted", event)
501
+
502
+ def on_candidate_rejected(self, event: CandidateRejectedEvent) -> None:
503
+ self._notify("on_candidate_rejected", event)
504
+
505
+ def on_merge_attempted(self, event: MergeAttemptedEvent) -> None:
506
+ self._notify("on_merge_attempted", event)
507
+
508
+ def on_merge_accepted(self, event: MergeAcceptedEvent) -> None:
509
+ self._notify("on_merge_accepted", event)
510
+
511
+ def on_merge_rejected(self, event: MergeRejectedEvent) -> None:
512
+ self._notify("on_merge_rejected", event)
513
+
514
+ def on_pareto_front_updated(self, event: ParetoFrontUpdatedEvent) -> None:
515
+ self._notify("on_pareto_front_updated", event)
516
+
517
+ def on_state_saved(self, event: StateSavedEvent) -> None:
518
+ self._notify("on_state_saved", event)
519
+
520
+ def on_budget_updated(self, event: BudgetUpdatedEvent) -> None:
521
+ self._notify("on_budget_updated", event)
522
+
523
+ def on_error(self, event: ErrorEvent) -> None:
524
+ self._notify("on_error", event)
525
+
526
+
527
+ def notify_callbacks(
528
+ callbacks: list[Any] | None,
529
+ method_name: str,
530
+ event: Any,
531
+ ) -> None:
532
+ """Utility function to notify a list of callbacks.
533
+
534
+ This is a convenience function for calling callback methods
535
+ without needing to wrap them in a CompositeCallback.
536
+
537
+ Args:
538
+ callbacks: List of callback objects, or None.
539
+ method_name: Name of the callback method to invoke.
540
+ event: The event TypedDict to pass to the callback method.
541
+ """
542
+ if callbacks is None:
543
+ return
544
+
545
+ for callback in callbacks:
546
+ method = getattr(callback, method_name, None)
547
+ if method is not None:
548
+ try:
549
+ method(event)
550
+ except Exception as e:
551
+ logger.warning(f"Callback {callback} failed on {method_name}: {e}")
@@ -0,0 +1,74 @@
1
+ """Data loader protocols and concrete helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Hashable, Protocol, Sequence, TypeVar, cast, runtime_checkable
6
+
7
+ from gepa.core.adapter import DataInst
8
+
9
+
10
+ class ComparableHashable(Hashable, Protocol):
11
+ """Protocol requiring hashing and rich comparison support."""
12
+
13
+ def __lt__(self, other: Any, /) -> bool: ...
14
+
15
+ def __gt__(self, other: Any, /) -> bool: ...
16
+
17
+ def __le__(self, other: Any, /) -> bool: ...
18
+
19
+ def __ge__(self, other: Any, /) -> bool: ...
20
+
21
+
22
+ DataId = TypeVar("DataId", bound=ComparableHashable)
23
+ """ Generic for the identifier for data examples """
24
+
25
+
26
+ @runtime_checkable
27
+ class DataLoader(Protocol[DataId, DataInst]):
28
+ """Minimal interface for retrieving validation examples keyed by opaque ids."""
29
+
30
+ def all_ids(self) -> Sequence[DataId]:
31
+ """Return the ordered universe of ids currently available. This may change over time."""
32
+ ...
33
+
34
+ def fetch(self, ids: Sequence[DataId]) -> list[DataInst]:
35
+ """Materialise the payloads corresponding to `ids`, preserving order."""
36
+ ...
37
+
38
+ def __len__(self) -> int:
39
+ """Return current number of items in the loader."""
40
+ ...
41
+
42
+
43
+ class MutableDataLoader(DataLoader[DataId, DataInst], Protocol):
44
+ """A data loader that can be mutated."""
45
+
46
+ def add_items(self, items: list[DataInst]) -> None:
47
+ """Add items to the loader."""
48
+
49
+
50
+ class ListDataLoader(MutableDataLoader[int, DataInst]):
51
+ """In-memory reference implementation backed by a list."""
52
+
53
+ def __init__(self, items: Sequence[DataInst]):
54
+ self.items = list(items)
55
+
56
+ def all_ids(self) -> Sequence[int]:
57
+ return list(range(len(self.items)))
58
+
59
+ def fetch(self, ids: Sequence[int]) -> list[DataInst]:
60
+ return [self.items[data_id] for data_id in ids]
61
+
62
+ def __len__(self) -> int:
63
+ return len(self.items)
64
+
65
+ def add_items(self, items: Sequence[DataInst]) -> None:
66
+ self.items.extend(items)
67
+
68
+
69
+ def ensure_loader(data_or_loader: Sequence[DataInst] | DataLoader[DataId, DataInst]) -> DataLoader[DataId, DataInst]:
70
+ if isinstance(data_or_loader, DataLoader):
71
+ return data_or_loader
72
+ if isinstance(data_or_loader, Sequence):
73
+ return cast(DataLoader[DataId, DataInst], ListDataLoader(data_or_loader))
74
+ raise TypeError(f"Unable to cast to a DataLoader type: {type(data_or_loader)}")