phronomy 0.26.0 → 0.28.0

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 (557) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +92 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +13 -3
  6. data/VERIFY.sh +27 -27
  7. data/benchmark/bench_agent_invoke.rb +26 -47
  8. data/benchmark/bench_context_assembler.rb +17 -15
  9. data/benchmark/bench_regression.rb +1 -1
  10. data/benchmark/bench_tool_schema.rb +1 -1
  11. data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
  12. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  13. data/docs/architecture/agent-context.md +4 -2
  14. data/docs/architecture/agent-transition-ownership.md +13 -0
  15. data/docs/architecture/backend-groups.md +152 -0
  16. data/docs/architecture/before-llm-input.md +9 -3
  17. data/docs/architecture/context-management.md +31 -1
  18. data/docs/architecture/context-preparation-steps.md +90 -0
  19. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  20. data/docs/architecture/execution-abstraction-review.md +88 -0
  21. data/docs/architecture/execution-boundaries.md +28 -0
  22. data/docs/architecture/execution-metadata-and-values.md +86 -0
  23. data/docs/architecture/generator-verifier-ownership.md +111 -0
  24. data/docs/architecture/multi-agent-handoff.md +11 -4
  25. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  26. data/docs/architecture/persistence.md +45 -4
  27. data/docs/architecture/r8-unit1.md +104 -0
  28. data/docs/architecture/r8-unit10.md +72 -0
  29. data/docs/architecture/r8-unit11.md +71 -0
  30. data/docs/architecture/r8-unit12.md +67 -0
  31. data/docs/architecture/r8-unit13.md +61 -0
  32. data/docs/architecture/r8-unit14.md +72 -0
  33. data/docs/architecture/r8-unit15.md +65 -0
  34. data/docs/architecture/r8-unit16.md +54 -0
  35. data/docs/architecture/r8-unit17.md +73 -0
  36. data/docs/architecture/r8-unit18.md +92 -0
  37. data/docs/architecture/r8-unit19.md +61 -0
  38. data/docs/architecture/r8-unit2.md +55 -0
  39. data/docs/architecture/r8-unit20.md +51 -0
  40. data/docs/architecture/r8-unit21.md +79 -0
  41. data/docs/architecture/r8-unit22.md +74 -0
  42. data/docs/architecture/r8-unit23.md +81 -0
  43. data/docs/architecture/r8-unit3.md +130 -0
  44. data/docs/architecture/r8-unit4.md +79 -0
  45. data/docs/architecture/r8-unit5.md +115 -0
  46. data/docs/architecture/r8-unit6.md +71 -0
  47. data/docs/architecture/r8-unit7.md +70 -0
  48. data/docs/architecture/r8-unit8.md +78 -0
  49. data/docs/architecture/r8-unit9.md +73 -0
  50. data/docs/architecture/refactoring-closure.md +343 -0
  51. data/docs/architecture/remaining-refactoring-plan.md +390 -0
  52. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  53. data/docs/architecture/storage-execution-boundaries.md +54 -0
  54. data/docs/architecture/tool-schema-recording-gap.md +56 -0
  55. data/docs/architecture/tracing.md +2 -2
  56. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  57. data/docs/architecture.md +222 -0
  58. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  59. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  60. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  61. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  62. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  63. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  64. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
  65. data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
  66. data/docs/decisions/032-storage-backend-composition.md +85 -0
  67. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  68. data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
  69. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  70. data/docs/decisions/036-context-contract-ownership.md +86 -0
  71. data/docs/decisions/037-common-definition-ownership.md +62 -0
  72. data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
  73. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
  74. data/docs/decisions/040-configuration-default-composition.md +105 -0
  75. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  76. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  77. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  78. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  79. data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
  80. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  81. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  82. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  83. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  84. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  85. data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
  86. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  87. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  88. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  89. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  90. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  91. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  92. data/docs/decisions/058-neutral-storage-primitives.md +83 -0
  93. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  94. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  95. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  96. data/docs/decisions/062-content-store-service.md +52 -0
  97. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  98. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  99. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  100. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  101. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  102. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  103. data/docs/decisions/README.md +52 -6
  104. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  105. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  106. data/docs/execution-boundaries-preview.md +45 -0
  107. data/docs/features.md +16 -5
  108. data/docs/getting-started.md +11 -8
  109. data/docs/migrations/0.15.md +5 -0
  110. data/docs/migrations/0.22.md +2 -2
  111. data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
  112. data/docs/migrations/handoff-runner-multi-agent.md +37 -0
  113. data/docs/migrations/neutral-storage-spi.md +43 -0
  114. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  115. data/docs/migrations/persistence-failure-contracts.md +67 -0
  116. data/docs/migrations/r8-unit10.md +36 -0
  117. data/docs/migrations/r8-unit11.md +33 -0
  118. data/docs/migrations/r8-unit12.md +31 -0
  119. data/docs/migrations/r8-unit13.md +36 -0
  120. data/docs/migrations/r8-unit14.md +31 -0
  121. data/docs/migrations/r8-unit15.md +31 -0
  122. data/docs/migrations/r8-unit16.md +26 -0
  123. data/docs/migrations/r8-unit17.md +28 -0
  124. data/docs/migrations/r8-unit18.md +29 -0
  125. data/docs/migrations/r8-unit19.md +28 -0
  126. data/docs/migrations/r8-unit20.md +24 -0
  127. data/docs/migrations/r8-unit21.md +28 -0
  128. data/docs/migrations/r8-unit22.md +29 -0
  129. data/docs/migrations/r8-unit23.md +20 -0
  130. data/docs/migrations/r8-unit4.md +67 -0
  131. data/docs/migrations/r8-unit5.md +75 -0
  132. data/docs/migrations/r8-unit6.md +109 -0
  133. data/docs/migrations/r8-unit7.md +31 -0
  134. data/docs/migrations/r8-unit8.md +33 -0
  135. data/docs/migrations/r8-unit9.md +28 -0
  136. data/docs/migrations/shared-state-multi-agent.md +44 -0
  137. data/docs/migrations/storage-async-client.md +103 -0
  138. data/docs/migrations/storage-backend-composition.md +117 -0
  139. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  140. data/docs/migrations/vector-async-clients.md +110 -0
  141. data/docs/persistence-backends.md +190 -215
  142. data/docs/runtime-and-concurrency.md +142 -32
  143. data/lib/phronomy/agent/admission.rb +78 -0
  144. data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
  145. data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
  146. data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
  147. data/lib/phronomy/agent/api/agent.rb +17 -0
  148. data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
  149. data/lib/phronomy/agent/async_event_api.rb +38 -33
  150. data/lib/phronomy/agent/base.rb +106 -294
  151. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  152. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  153. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  154. data/lib/phronomy/agent/context_importer.rb +2 -2
  155. data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
  156. data/lib/phronomy/agent/control_request.rb +21 -0
  157. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  158. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
  159. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  160. data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
  161. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
  162. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
  163. data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
  164. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  165. data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
  166. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
  167. data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
  168. data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
  169. data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
  170. data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
  171. data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
  172. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  173. data/lib/phronomy/agent/execution_change.rb +161 -0
  174. data/lib/phronomy/agent/execution_environment.rb +36 -0
  175. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  176. data/lib/phronomy/agent/execution_observation.rb +35 -0
  177. data/lib/phronomy/agent/filterable.rb +182 -0
  178. data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
  179. data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
  180. data/lib/phronomy/agent/handoff_error.rb +7 -0
  181. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  182. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  183. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  184. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  185. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  186. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  187. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
  188. data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
  189. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  190. data/lib/phronomy/agent/persistence/codec.rb +338 -0
  191. data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
  192. data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
  193. data/lib/phronomy/agent/persistence/records.rb +33 -0
  194. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  195. data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
  196. data/lib/phronomy/agent/persistence/watermark.rb +29 -0
  197. data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
  198. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
  199. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
  200. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
  201. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
  202. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  203. data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
  204. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  205. data/lib/phronomy/agent/retention.rb +17 -0
  206. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  207. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  208. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  209. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  210. data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
  211. data/lib/phronomy/agent/saved_context_reader.rb +55 -0
  212. data/lib/phronomy/agent/settings.rb +47 -0
  213. data/lib/phronomy/agent/state_writer.rb +166 -0
  214. data/lib/phronomy/agent/store.rb +253 -0
  215. data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
  216. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  217. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  218. data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
  219. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
  220. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  221. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  222. data/lib/phronomy/common/configuration_error.rb +7 -0
  223. data/lib/phronomy/common/error.rb +5 -0
  224. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  225. data/lib/phronomy/common/values/serializable.rb +32 -0
  226. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  227. data/lib/phronomy/content_store/storage_schema.rb +12 -0
  228. data/lib/phronomy/content_store/stored_contents.rb +44 -0
  229. data/lib/phronomy/context/assembly.rb +202 -0
  230. data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
  231. data/lib/phronomy/context/candidate.rb +51 -0
  232. data/lib/phronomy/context/constraint.rb +47 -0
  233. data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
  234. data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
  235. data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
  236. data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
  237. data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
  238. data/lib/phronomy/context/default_policy.rb +140 -0
  239. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  240. data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
  241. data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
  242. data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
  243. data/lib/phronomy/context/manifest_error.rb +10 -0
  244. data/lib/phronomy/context/prompt_template.rb +98 -0
  245. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  246. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  247. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  248. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  249. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  250. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  251. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  252. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  253. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  254. data/lib/phronomy/embeddings/base.rb +43 -0
  255. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  256. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  257. data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
  258. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  259. data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
  260. data/lib/phronomy/engine/event_loop.rb +164 -630
  261. data/lib/phronomy/engine/execution_binding.rb +23 -0
  262. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  263. data/lib/phronomy/engine/fsm_protocol.rb +9 -0
  264. data/lib/phronomy/engine/fsm_session.rb +37 -30
  265. data/lib/phronomy/engine/metrics.rb +28 -0
  266. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  267. data/lib/phronomy/engine/runtime.rb +104 -95
  268. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  269. data/lib/phronomy/execution/async_operation.rb +41 -0
  270. data/lib/phronomy/execution/backpressure_error.rb +7 -0
  271. data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
  272. data/lib/phronomy/execution/cancellation_error.rb +7 -0
  273. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
  274. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  275. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  276. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  277. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  278. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  279. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  280. data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
  281. data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
  282. data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
  283. data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
  284. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  285. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  286. data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
  287. data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
  288. data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
  289. data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
  290. data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
  291. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  292. data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
  293. data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
  294. data/lib/phronomy/execution/runnable.rb +24 -0
  295. data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
  296. data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
  297. data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
  298. data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
  299. data/lib/phronomy/execution/timeout_error.rb +7 -0
  300. data/lib/phronomy/execution/wait_policy.rb +24 -0
  301. data/lib/phronomy/filter/filter_block_error.rb +14 -0
  302. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  303. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  304. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  305. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  306. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  307. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  308. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  309. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  310. data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
  311. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  312. data/lib/phronomy/llm_adapter/base.rb +49 -68
  313. data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
  314. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  315. data/lib/phronomy/llm_adapter/message.rb +62 -0
  316. data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
  317. data/lib/phronomy/llm_adapter/request.rb +79 -0
  318. data/lib/phronomy/llm_adapter/response.rb +36 -0
  319. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  320. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  321. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  322. data/lib/phronomy/llm_adapter.rb +3 -16
  323. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  324. data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
  325. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  326. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  327. data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
  328. data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
  329. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  330. data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
  331. data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
  332. data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
  333. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  334. data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
  335. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  336. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  337. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  338. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
  339. data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
  340. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  341. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  342. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  343. data/lib/phronomy/multi_agent/store.rb +156 -0
  344. data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
  345. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  346. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
  347. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  348. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  349. data/lib/phronomy/persistence/content_repository.rb +26 -0
  350. data/lib/phronomy/persistence/errors.rb +16 -0
  351. data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
  352. data/lib/phronomy/persistence/persistence.rb +23 -0
  353. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  354. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  355. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  356. data/lib/phronomy/persistence/transaction.rb +86 -0
  357. data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
  358. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  359. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  360. data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
  361. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  362. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  363. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  364. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  365. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  366. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  367. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  368. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  369. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  370. data/lib/phronomy/storage/async/async_client.rb +60 -0
  371. data/lib/phronomy/storage/backend.rb +107 -0
  372. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  373. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  374. data/lib/phronomy/storage/blobs.rb +31 -0
  375. data/lib/phronomy/storage/condition.rb +25 -0
  376. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  377. data/lib/phronomy/storage/conflict_error.rb +9 -0
  378. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  379. data/lib/phronomy/storage/entry.rb +33 -0
  380. data/lib/phronomy/storage/guard_ref.rb +13 -0
  381. data/lib/phronomy/storage/not_found_error.rb +9 -0
  382. data/lib/phronomy/storage/record_codec.rb +177 -0
  383. data/lib/phronomy/storage/records.rb +61 -0
  384. data/lib/phronomy/storage/resource.rb +126 -0
  385. data/lib/phronomy/storage/scope.rb +25 -0
  386. data/lib/phronomy/storage/serialization_error.rb +9 -0
  387. data/lib/phronomy/storage/streams.rb +44 -0
  388. data/lib/phronomy/storage/transaction_error.rb +10 -0
  389. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  390. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  391. data/lib/phronomy/storage/validation.rb +53 -0
  392. data/lib/phronomy/storage/view.rb +131 -0
  393. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  394. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  395. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  396. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  397. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
  398. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
  399. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
  400. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  401. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
  402. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  403. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
  404. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  405. data/lib/phronomy/tool/authorization.rb +77 -0
  406. data/lib/phronomy/tool/base.rb +549 -9
  407. data/lib/phronomy/tool/call_request.rb +40 -0
  408. data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
  409. data/lib/phronomy/tool/operation.rb +88 -0
  410. data/lib/phronomy/tool/schema.rb +214 -0
  411. data/lib/phronomy/tool/settings.rb +31 -0
  412. data/lib/phronomy/tool/tool_error.rb +7 -0
  413. data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
  414. data/lib/phronomy/tools/agent.rb +22 -90
  415. data/lib/phronomy/tools/mcp.rb +21 -14
  416. data/lib/phronomy/tools/vector_search.rb +4 -4
  417. data/lib/phronomy/tracing/automatic.rb +11 -6
  418. data/lib/phronomy/tracing/base.rb +1 -1
  419. data/lib/phronomy/tracing/observation.rb +37 -0
  420. data/lib/phronomy/tracing/settings.rb +36 -0
  421. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  422. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  423. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  424. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  425. data/lib/phronomy/vector_store/base.rb +118 -49
  426. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  427. data/lib/phronomy/vector_store.rb +2 -17
  428. data/lib/phronomy/version.rb +1 -1
  429. data/lib/phronomy/workflow/completion.rb +11 -0
  430. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  431. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  432. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
  433. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  434. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  435. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
  436. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
  437. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  438. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  439. data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
  440. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  441. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  442. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  443. data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
  444. data/lib/phronomy.rb +97 -98
  445. data/scripts/api_snapshot.rb +36 -16
  446. data/scripts/storage_spi_snapshot.rb +36 -0
  447. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  448. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  449. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  450. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  451. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  452. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  453. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  454. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  455. data/sig/phronomy/agent/admission.rbs +19 -0
  456. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  457. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  458. data/sig/phronomy/agent/store.rbs +73 -0
  459. data/sig/phronomy/agent.rbs +14 -139
  460. data/sig/phronomy/common.rbs +7 -0
  461. data/sig/phronomy/content_store/contracts.rbs +13 -0
  462. data/sig/phronomy/context.rbs +152 -0
  463. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  464. data/sig/phronomy/embeddings/base.rbs +17 -0
  465. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  466. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  467. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  468. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  469. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  470. data/sig/phronomy/engine/observability.rbs +13 -0
  471. data/sig/phronomy/execution/async_operation.rbs +7 -0
  472. data/sig/phronomy/execution/blocking.rbs +5 -0
  473. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  474. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  475. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  476. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  477. data/sig/phronomy/execution/errors.rbs +7 -0
  478. data/sig/phronomy/execution/execution.rbs +41 -0
  479. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  480. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  481. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  482. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  483. data/sig/phronomy/execution/task_result.rbs +29 -0
  484. data/sig/phronomy/extensions.rbs +0 -21
  485. data/sig/phronomy/handoff.rbs +12 -4
  486. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  487. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  488. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  489. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  490. data/sig/phronomy/llm_context_window.rbs +10 -0
  491. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  492. data/sig/phronomy/multi_agent/store.rbs +54 -0
  493. data/sig/phronomy/multi_agent.rbs +24 -3
  494. data/sig/phronomy/persistence/errors.rbs +18 -0
  495. data/sig/phronomy/persistence/migration.rbs +13 -0
  496. data/sig/phronomy/persistence/transaction.rbs +19 -0
  497. data/sig/phronomy/persistence.rbs +3 -185
  498. data/sig/phronomy/persistence_composition.rbs +19 -0
  499. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  500. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  501. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  502. data/sig/phronomy/storage/contracts.rbs +160 -0
  503. data/sig/phronomy/tool.rbs +58 -5
  504. data/sig/phronomy/tracing/observation.rbs +7 -0
  505. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  506. data/sig/phronomy/vector_store/base.rbs +23 -0
  507. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  508. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  509. data/sig/phronomy/workflow/store.rbs +8 -0
  510. data/sig/phronomy/workflow.rbs +1 -1
  511. data/sig/phronomy.rbs +0 -49
  512. metadata +462 -130
  513. data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
  514. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  515. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  516. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  517. data/lib/phronomy/agent/context/capability/base.rb +0 -507
  518. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  519. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  520. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  521. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  522. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  523. data/lib/phronomy/agent/handoff_request.rb +0 -45
  524. data/lib/phronomy/agent/handoff_runner.rb +0 -178
  525. data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
  526. data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
  527. data/lib/phronomy/agent/recovery_support.rb +0 -504
  528. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  529. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  530. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  531. data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
  532. data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
  533. data/lib/phronomy/configuration.rb +0 -59
  534. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  535. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  536. data/lib/phronomy/generator_verifier.rb +0 -369
  537. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  538. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  539. data/lib/phronomy/metrics.rb +0 -26
  540. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  541. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  542. data/lib/phronomy/persistence/in_memory.rb +0 -690
  543. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  544. data/lib/phronomy/persistence.rb +0 -276
  545. data/lib/phronomy/recovery.rb +0 -186
  546. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  547. data/lib/phronomy/runnable.rb +0 -54
  548. data/lib/phronomy/token_usage.rb +0 -85
  549. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  550. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  551. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  552. data/lib/phronomy/workflow_recovery.rb +0 -123
  553. data/sig/phronomy/llm_adapter.rbs +0 -11
  554. data/sig/phronomy/runtime.rbs +0 -76
  555. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  556. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  557. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Storage
5
+ # Root handles route to the current scope; bound handles cannot outlive it.
6
+ # @api public
7
+ class View
8
+ def initialize(backend, scope: nil, context: nil)
9
+ @backend, @scope, @context = backend, scope, context
10
+ @handles = {}
11
+ end
12
+
13
+ # @api public
14
+ def records(resource) = handle(resource, :records, Records)
15
+ # @api public
16
+ def streams(resource) = handle(resource, :streams, Streams)
17
+ # @api public
18
+ def blobs(resource) = handle(resource, :blobs, Blobs)
19
+
20
+ # Acquire stable anchors before evaluating conditions in the same view.
21
+ # @api public
22
+ def check!(guards:, conditions:)
23
+ validate!
24
+ raise ArgumentError, "guards and conditions must be arrays" unless guards.is_a?(Array) && conditions.is_a?(Array)
25
+ guards.each do |guard|
26
+ raise ArgumentError, "expected GuardRef" unless guard.is_a?(GuardRef)
27
+ resolve(guard.resource, :records)
28
+ end
29
+ conditions.each do |condition|
30
+ case condition
31
+ when Condition::RevisionIs then resolve(condition.resource, :records)
32
+ when Condition::StreamHeadIs then resolve(condition.resource, :streams)
33
+ when Condition::NoRows then resolve(condition.resource, :records).index_values(condition.index, condition.equals)
34
+ else raise ArgumentError, "unsupported condition"
35
+ end
36
+ require_guard!(condition, guards)
37
+ end
38
+ atomic do |bound|
39
+ guards.uniq.sort_by { |g| [resolve(g.resource, :records).id.b, g.key.b] }.each do |guard|
40
+ bound.perform(:lock_guard, resolve(guard.resource, :records), key: guard.key)
41
+ end
42
+ conditions.each do |condition|
43
+ matched = case condition
44
+ when Condition::RevisionIs then bound.records(condition.resource).read(condition.key)&.revision == condition.expected
45
+ when Condition::StreamHeadIs then bound.streams(condition.resource).head(stream: condition.stream) == condition.expected
46
+ when Condition::NoRows then bound.records(condition.resource).scan(index: condition.index, equals: condition.equals, limit: 1).empty?
47
+ end
48
+ raise ConditionFailedError, condition unless matched
49
+ end
50
+ true
51
+ end
52
+ end
53
+
54
+ # Keeps domain encoding/response validation inside the physical transaction.
55
+ # @api private
56
+ def atomic
57
+ validate!
58
+ unless @scope
59
+ current = @backend.current_view
60
+ return current.atomic { |bound| yield bound } if current
61
+ return @backend.transaction { |bound| bound.atomic { yield bound } }
62
+ end
63
+ completed = false
64
+ begin
65
+ result = yield self
66
+ @scope.check!
67
+ completed = true
68
+ result
69
+ ensure
70
+ @scope.fail! unless completed
71
+ end
72
+ end
73
+
74
+ # @api private
75
+ def perform(operation, resource, **arguments)
76
+ atomic { |bound| bound.dispatch(operation, resource, **arguments) }
77
+ end
78
+
79
+ # @api private
80
+ def dispatch(operation, resource, **arguments)
81
+ validate!
82
+ @backend.execute(@context, operation, resource, **arguments)
83
+ end
84
+
85
+ # @api private
86
+ def validate!
87
+ @scope&.check!
88
+ true
89
+ end
90
+
91
+ private
92
+
93
+ def require_guard!(condition, guards)
94
+ resource = @backend.resources.fetch(condition.resource.is_a?(Resource) ? condition.resource.id : condition.resource)
95
+ guard = resource.guard
96
+ return unless guard
97
+ key = case condition
98
+ when Condition::RevisionIs
99
+ if guard[:via] == :key
100
+ condition.key
101
+ else
102
+ raise ArgumentError, "revision checks require a key-based guard"
103
+ end
104
+ when Condition::StreamHeadIs then condition.stream
105
+ when Condition::NoRows
106
+ condition.equals.fetch(guard[:via]) { raise ArgumentError, "condition must constrain its guard attribute" }
107
+ end
108
+ covered = guards.any? do |candidate|
109
+ resolve(candidate.resource, :records).id == guard[:resource] && candidate.key == key
110
+ end
111
+ raise ArgumentError, "condition requires its declared guard" unless covered
112
+ end
113
+
114
+ def resolve(resource, kind)
115
+ id = resource.is_a?(Resource) ? resource.id : resource
116
+ registered = @backend.resources[id]
117
+ valid = registered && registered.kind == kind && (!resource.is_a?(Resource) || registered.equal?(resource))
118
+ unless valid
119
+ raise UnsupportedBackendError, "unregistered or mismatched #{kind} resource: #{id}"
120
+ end
121
+ registered
122
+ end
123
+
124
+ def handle(resource, kind, type)
125
+ validate!
126
+ registered = resolve(resource, kind)
127
+ @handles[registered.id] ||= type.new(self, registered)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -19,7 +19,7 @@ module Phronomy
19
19
  end
20
20
 
21
21
  def total_usage
22
- @results.map(&:usage).compact.reduce(Phronomy::TokenUsage.zero, :+)
22
+ @results.map(&:usage).compact.reduce(Phronomy::LLMAdapter::TokenUsage.zero, :+)
23
23
  end
24
24
 
25
25
  def average_latency_ms
@@ -5,6 +5,19 @@ module Phronomy
5
5
  module Eval
6
6
  module Scorer
7
7
  class LlmJudge < Base
8
+ CLIENT_FACTORIES = {}
9
+ private_constant :CLIENT_FACTORIES
10
+
11
+ # One-time boot binding, not an application extension registry. The
12
+ # factory runs for each score, after its Request has been prepared.
13
+ # @api private
14
+ def self.install_client_factory(factory)
15
+ raise ArgumentError, "factory must respond to call" unless factory.respond_to?(:call)
16
+
17
+ CLIENT_FACTORIES.replace(client: factory).freeze
18
+ nil
19
+ end
20
+
8
21
  DEFAULT_PROMPT = <<~PROMPT
9
22
  You are an impartial judge evaluating the quality of an AI assistant response.
10
23
  Rate the response on a scale from 0.0 (completely wrong or unhelpful) to 1.0 (perfect).
@@ -32,9 +45,12 @@ module Phronomy
32
45
  expected: expected.to_s,
33
46
  actual: actual.to_s
34
47
  )
35
- response = Phronomy::Runtime.instance.offload.submit do
36
- RubyLLM.chat(model: @model, provider: @provider, assume_model_exists: @assume_model_exists).ask(prompt)
37
- end.wait_result
48
+ request = Phronomy::LLMAdapter::Request.new(
49
+ model_config: {"model" => @model, "provider" => @provider&.to_s,
50
+ "assume_model_exists" => @assume_model_exists}.compact,
51
+ message: prompt
52
+ )
53
+ response = CLIENT_FACTORIES.fetch(:client).call.complete_async(request).wait_result
38
54
  response.content.to_s.strip.scan(/-?\d+\.?\d*/).first.to_f.clamp(0.0, 1.0)
39
55
  rescue => error
40
56
  raise if @raise_on_error
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.shared_examples "a persistence content store" do
4
- let(:content_store) { persistence.contents }
4
+ let(:content_store) { stores.agent.contents }
5
5
 
6
6
  it "returns the same content_id for the same bytes" do
7
7
  first = content_store.put("same".b, canonicalization_version: 1)
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "a Journal repository" do
6
- let(:journal_repository) { persistence.journals }
6
+ let(:journal_repository) { stores.agent.journals }
7
7
  let(:journal_agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "journal-agent-#{SecureRandom.uuid}",
@@ -25,7 +25,7 @@ RSpec.shared_examples "a Journal repository" do
25
25
  end
26
26
 
27
27
  before do
28
- persistence.agents.create(journal_agent_root)
28
+ stores.agent.agents.create(journal_agent_root)
29
29
  end
30
30
 
31
31
  it "appends records at the expected position and assigns durable sequences" do
@@ -3,6 +3,9 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "a Persistence backend" do
6
+ include_examples "neutral storage primitives"
7
+ include_examples "storage transaction boundaries"
8
+
6
9
  let(:backend_agent_root) do
7
10
  Phronomy::Agent::AgentRoot.create(
8
11
  agent_id: "backend-agent-#{SecureRandom.uuid}",
@@ -23,27 +26,26 @@ RSpec.shared_examples "a Persistence backend" do
23
26
  end
24
27
 
25
28
  it "advertises every required capability" do
26
- Phronomy::Persistence::REQUIRED_CAPABILITIES.each do |name, required_value|
27
- expect(persistence.capabilities[name]).to eq(required_value)
29
+ Phronomy::Storage::Backend::REQUIRED_CAPABILITIES.each do |name, required_value|
30
+ expect(stores.coordinator.backend.capabilities[name]).to eq(required_value)
28
31
  end
29
32
  end
30
33
 
31
- it "yields a transaction view that exposes the complete durable SPI" do
32
- persistence.transaction do |tx|
33
- expect(tx).to respond_to(
34
- :contents,
35
- :agents,
36
- :journals,
37
- :executions,
38
- :workflow_states,
39
- :handoff_states, :teams, :team_executions,
40
- :assert_agent_watermark!
41
- )
34
+ it "binds each domain to its own record protocol in one common scope" do
35
+ stores.coordinator.atomic do |scope|
36
+ stores.agent.participate(scope) do |records|
37
+ expect(records).to respond_to(:contents, :agents, :journals, :executions, :retentions, :cancellations, :assert_agent_watermark!)
38
+ expect(records).not_to respond_to(:teams, :team_executions, :workflow_states)
39
+ end
40
+ stores.multi_agent.participate(scope) do |records|
41
+ expect(records).to respond_to(:contents, :teams, :team_executions, :handoff_states)
42
+ expect(records).not_to respond_to(:agents, :executions, :workflow_states)
43
+ end
42
44
  end
43
45
  end
44
46
 
45
47
  it "returns the transaction block result" do
46
- expect(persistence.transaction { |_tx| :contract_result }).to eq(:contract_result)
48
+ expect(stores.agent.transaction { |_tx| :contract_result }).to eq(:contract_result)
47
49
  end
48
50
 
49
51
  it "commits changes across durable repositories as one transaction" do
@@ -52,7 +54,7 @@ RSpec.shared_examples "a Persistence backend" do
52
54
  workflow_id = "workflow-#{SecureRandom.uuid}"
53
55
  content_id = nil
54
56
 
55
- persistence.transaction do |tx|
57
+ stores.agent.transaction do |tx, scope|
56
58
  content_id = tx.contents.put_text("committed")
57
59
  tx.agents.create(root)
58
60
  appended = tx.journals.append(
@@ -70,11 +72,13 @@ RSpec.shared_examples "a Persistence backend" do
70
72
  ]
71
73
  )
72
74
  tx.executions.create_active(execution)
73
- tx.workflow_states.save(
74
- workflow_id,
75
- expected_revision: nil,
76
- snapshot: {fields: {value: "committed"}, phase: "pause"}
77
- )
75
+ scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
76
+ workflow.save(
77
+ workflow_id,
78
+ expected_revision: nil,
79
+ snapshot: {fields: {value: "committed"}, phase: "pause"}
80
+ )
81
+ end
78
82
 
79
83
  updated_root = root.with(
80
84
  agent_revision: 1,
@@ -84,12 +88,12 @@ RSpec.shared_examples "a Persistence backend" do
84
88
  tx.agents.save(root.agent_id, expected_revision: 0, root: updated_root)
85
89
  end
86
90
 
87
- expect(persistence.contents.exist?(content_id)).to be(true)
88
- expect(persistence.agents.load(root.agent_id).agent_revision).to eq(1)
89
- expect(persistence.journals.head(root.agent_id)).to eq(1)
90
- expect(persistence.executions.load(execution.execution_id).execution_id)
91
+ expect(stores.agent.contents.exist?(content_id)).to be(true)
92
+ expect(stores.agent.agents.load(root.agent_id).agent_revision).to eq(1)
93
+ expect(stores.agent.journals.head(root.agent_id)).to eq(1)
94
+ expect(stores.agent.executions.load(execution.execution_id).execution_id)
91
95
  .to eq(execution.execution_id)
92
- expect(persistence.workflow_states.load(workflow_id)).not_to be_nil
96
+ expect(stores.workflow.load(workflow_id)).not_to be_nil
93
97
  end
94
98
 
95
99
  it "rolls back all durable repositories when the transaction block raises" do
@@ -99,7 +103,7 @@ RSpec.shared_examples "a Persistence backend" do
99
103
  content_id = nil
100
104
 
101
105
  expect do
102
- persistence.transaction do |tx|
106
+ stores.agent.transaction do |tx, scope|
103
107
  content_id = tx.contents.put_text("temporary-#{SecureRandom.uuid}")
104
108
  tx.agents.create(root)
105
109
  tx.journals.append(
@@ -117,32 +121,34 @@ RSpec.shared_examples "a Persistence backend" do
117
121
  ]
118
122
  )
119
123
  tx.executions.create_active(execution)
120
- tx.workflow_states.save(
121
- workflow_id,
122
- expected_revision: nil,
123
- snapshot: {fields: {value: "temporary"}, phase: "pause"}
124
- )
124
+ scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
125
+ workflow.save(
126
+ workflow_id,
127
+ expected_revision: nil,
128
+ snapshot: {fields: {value: "temporary"}, phase: "pause"}
129
+ )
130
+ end
125
131
  raise "rollback-contract"
126
132
  end
127
133
  end.to raise_error("rollback-contract")
128
134
 
129
- expect(persistence.contents.exist?(content_id)).to be(false)
135
+ expect(stores.agent.contents.exist?(content_id)).to be(false)
130
136
  expect do
131
- persistence.agents.load(root.agent_id)
137
+ stores.agent.agents.load(root.agent_id)
132
138
  end.to raise_error(Phronomy::Persistence::NotFoundError)
133
- expect(persistence.journals.head(root.agent_id)).to eq(0)
139
+ expect(stores.agent.journals.head(root.agent_id)).to eq(0)
134
140
  expect do
135
- persistence.executions.load(execution.execution_id)
141
+ stores.agent.executions.load(execution.execution_id)
136
142
  end.to raise_error(Phronomy::Persistence::NotFoundError)
137
- expect(persistence.workflow_states.load(workflow_id)).to be_nil
143
+ expect(stores.workflow.load(workflow_id)).to be_nil
138
144
  end
139
145
 
140
146
  it "accepts the current Agent revision and Journal position watermark" do
141
147
  root = backend_agent_root
142
- persistence.agents.create(root)
148
+ stores.agent.agents.create(root)
143
149
 
144
150
  expect(
145
- persistence.assert_agent_watermark!(
151
+ stores.agent.assert_agent_watermark!(
146
152
  agent_id: root.agent_id,
147
153
  agent_revision: root.agent_revision,
148
154
  journal_position: root.journal_position
@@ -152,12 +158,12 @@ RSpec.shared_examples "a Persistence backend" do
152
158
 
153
159
  it "raises ConflictError when the durable Agent revision has advanced" do
154
160
  root = backend_agent_root
155
- persistence.agents.create(root)
161
+ stores.agent.agents.create(root)
156
162
  advanced = root.with(agent_revision: 1)
157
- persistence.agents.save(root.agent_id, expected_revision: 0, root: advanced)
163
+ stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
158
164
 
159
165
  expect do
160
- persistence.assert_agent_watermark!(
166
+ stores.agent.assert_agent_watermark!(
161
167
  agent_id: root.agent_id,
162
168
  agent_revision: 0,
163
169
  journal_position: 0
@@ -167,8 +173,8 @@ RSpec.shared_examples "a Persistence backend" do
167
173
 
168
174
  it "raises ConflictError when the durable Journal position has advanced" do
169
175
  root = backend_agent_root
170
- persistence.agents.create(root)
171
- persistence.journals.append(
176
+ stores.agent.agents.create(root)
177
+ stores.agent.journals.append(
172
178
  root.agent_id,
173
179
  expected_position: 0,
174
180
  records: [
@@ -183,7 +189,7 @@ RSpec.shared_examples "a Persistence backend" do
183
189
  )
184
190
 
185
191
  expect do
186
- persistence.assert_agent_watermark!(
192
+ stores.agent.assert_agent_watermark!(
187
193
  agent_id: root.agent_id,
188
194
  agent_revision: 0,
189
195
  journal_position: 0
@@ -193,13 +199,13 @@ RSpec.shared_examples "a Persistence backend" do
193
199
 
194
200
  it "rolls back earlier writes when a watermark precondition fails" do
195
201
  root = backend_agent_root
196
- persistence.agents.create(root)
202
+ stores.agent.agents.create(root)
197
203
  advanced = root.with(agent_revision: 1)
198
- persistence.agents.save(root.agent_id, expected_revision: 0, root: advanced)
204
+ stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
199
205
  temporary_content_id = nil
200
206
 
201
207
  expect do
202
- persistence.transaction do |tx|
208
+ stores.agent.transaction do |tx, scope|
203
209
  temporary_content_id = tx.contents.put_text(
204
210
  "watermark-rollback-#{SecureRandom.uuid}"
205
211
  )
@@ -211,6 +217,6 @@ RSpec.shared_examples "a Persistence backend" do
211
217
  end
212
218
  end.to raise_error(Phronomy::Persistence::ConflictError)
213
219
 
214
- expect(persistence.contents.exist?(temporary_content_id)).to be(false)
220
+ expect(stores.agent.contents.exist?(temporary_content_id)).to be(false)
215
221
  end
216
222
  end
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "a workflow state repository" do
6
- let(:repository) { persistence.workflow_states }
6
+ let(:repository) { stores.workflow }
7
7
 
8
8
  def workflow_contract_value(hash, key)
9
9
  hash.key?(key) ? hash[key] : hash[key.to_s]
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "an Agent repository" do
6
- let(:agent_repository) { persistence.agents }
6
+ let(:agent_repository) { stores.agent.agents }
7
7
  let(:agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "contract-agent-#{SecureRandom.uuid}",
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "an Execution repository" do
6
- let(:execution_repository) { persistence.executions }
6
+ let(:execution_repository) { stores.agent.executions }
7
7
  let(:execution_agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "execution-agent-#{SecureRandom.uuid}",
@@ -27,7 +27,7 @@ RSpec.shared_examples "an Execution repository" do
27
27
  end
28
28
 
29
29
  before do
30
- persistence.agents.create(execution_agent_root)
30
+ stores.agent.agents.create(execution_agent_root)
31
31
  end
32
32
 
33
33
  it "creates and loads an active execution" do
@@ -68,7 +68,7 @@ RSpec.shared_examples "an Execution repository" do
68
68
  agent_definition_id: "contract-agent",
69
69
  agent_definition_version: 1
70
70
  )
71
- persistence.agents.create(other_root)
71
+ stores.agent.agents.create(other_root)
72
72
 
73
73
  expect do
74
74
  execution_repository.create_active(build_contract_execution(execution_agent_root))
@@ -118,7 +118,7 @@ RSpec.shared_examples "an Execution repository" do
118
118
  agent_definition_id: "contract-agent",
119
119
  agent_definition_version: 1
120
120
  )
121
- persistence.agents.create(other_root)
121
+ stores.agent.agents.create(other_root)
122
122
  other = build_contract_execution(other_root).with(
123
123
  execution_revision: 1,
124
124
  status: :active,
@@ -188,7 +188,7 @@ RSpec.shared_examples "an Execution repository" do
188
188
  agent_definition_id: "contract-agent",
189
189
  agent_definition_version: 1
190
190
  )
191
- persistence.agents.create(other_root)
191
+ stores.agent.agents.create(other_root)
192
192
  own = build_contract_execution(execution_agent_root)
193
193
  other = build_contract_execution(other_root)
194
194
  execution_repository.create_active(own)
@@ -19,7 +19,7 @@ RSpec.shared_context "coordination repository values" do
19
19
  end
20
20
  let(:coordination_handoff) do
21
21
  now = Time.now.utc.iso8601(6)
22
- Phronomy::Agent::HandoffState.new(main_agent_id: SecureRandom.uuid, handoff_revision: 1,
22
+ Phronomy::MultiAgent::HandoffState.new(main_agent_id: SecureRandom.uuid, handoff_revision: 1,
23
23
  active_agent_id: "contract-target", active_handoff_context_ref: nil, phase: "target_pending",
24
24
  pending_source_execution_id: "source-execution", pending_target_execution_id: "target-execution",
25
25
  created_at: now, updated_at: now, metadata: {})
@@ -30,26 +30,26 @@ RSpec.shared_examples "a Handoff state repository" do
30
30
  include_context "coordination repository values"
31
31
 
32
32
  it "returns nil only for an authoritative absent Handoff anchor" do
33
- expect(persistence.handoff_states.load(SecureRandom.uuid)).to be_nil
33
+ expect(stores.multi_agent.handoff_states.load(SecureRandom.uuid)).to be_nil
34
34
  end
35
35
 
36
36
  it "round-trips the immutable Handoff snapshot and rejects stale routing CAS" do
37
37
  value = coordination_handoff
38
- persistence.handoff_states.save(value.main_agent_id, expected_revision: nil, state: value)
39
- loaded = persistence.handoff_states.load(value.main_agent_id)
38
+ stores.multi_agent.handoff_states.save(value.main_agent_id, expected_revision: nil, state: value)
39
+ loaded = stores.multi_agent.handoff_states.load(value.main_agent_id)
40
40
  expect(loaded.to_h).to eq(value.to_h)
41
41
  expect(loaded).to be_frozen
42
42
  updated = value.with(phase: "stable")
43
- persistence.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
43
+ stores.multi_agent.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
44
44
  expect do
45
- persistence.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
45
+ stores.multi_agent.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
46
46
  end.to raise_error(Phronomy::Persistence::ConflictError)
47
- expect(persistence.handoff_states.load(value.main_agent_id).handoff_revision).to eq(2)
47
+ expect(stores.multi_agent.handoff_states.load(value.main_agent_id).handoff_revision).to eq(2)
48
48
  end
49
49
 
50
50
  it "rejects a snapshot for a different routing anchor" do
51
51
  expect do
52
- persistence.handoff_states.save("other", expected_revision: nil, state: coordination_handoff)
52
+ stores.multi_agent.handoff_states.save("other", expected_revision: nil, state: coordination_handoff)
53
53
  end.to raise_error(Phronomy::Persistence::SerializationError)
54
54
  end
55
55
  end
@@ -58,51 +58,51 @@ RSpec.shared_examples "a Team repository" do
58
58
  include_context "coordination repository values"
59
59
 
60
60
  it "round-trips a Team lineage and rejects duplicate creation" do
61
- persistence.teams.create(coordination_team)
62
- expect(persistence.teams.load(coordination_team.team_id).to_h).to eq(coordination_team.to_h)
63
- expect { persistence.teams.create(coordination_team) }.to raise_error(Phronomy::Persistence::ConflictError)
61
+ stores.multi_agent.teams.create(coordination_team)
62
+ expect(stores.multi_agent.teams.load(coordination_team.team_id).to_h).to eq(coordination_team.to_h)
63
+ expect { stores.multi_agent.teams.create(coordination_team) }.to raise_error(Phronomy::Persistence::ConflictError)
64
64
  end
65
65
 
66
66
  it "rejects a stale Team revision" do
67
- persistence.teams.create(coordination_team)
67
+ stores.multi_agent.teams.create(coordination_team)
68
68
  updated = coordination_team.with(lifecycle_status: "active")
69
- persistence.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
69
+ stores.multi_agent.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
70
70
  expect do
71
- persistence.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
71
+ stores.multi_agent.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
72
72
  end.to raise_error(Phronomy::Persistence::ConflictError)
73
73
  end
74
74
 
75
75
  it "raises NotFoundError for an absent Team" do
76
- expect { persistence.teams.load(SecureRandom.uuid) }.to raise_error(Phronomy::Persistence::NotFoundError)
76
+ expect { stores.multi_agent.teams.load(SecureRandom.uuid) }.to raise_error(Phronomy::Persistence::NotFoundError)
77
77
  end
78
78
  end
79
79
 
80
80
  RSpec.shared_examples "a Team execution repository" do
81
81
  include_context "coordination repository values"
82
- before { persistence.teams.create(coordination_team) }
82
+ before { stores.multi_agent.teams.create(coordination_team) }
83
83
 
84
84
  it "atomically admits at most one active run per Team" do
85
- persistence.team_executions.create_active(coordination_run)
85
+ stores.multi_agent.team_executions.create_active(coordination_run)
86
86
  other = coordination_run.with(team_execution_id: SecureRandom.uuid, execution_revision: 0)
87
- expect { persistence.team_executions.create_active(other) }.to raise_error(Phronomy::AgentBusyError)
88
- expect(persistence.team_executions.list_active(coordination_team.team_id).map(&:team_execution_id)).to eq([coordination_run.team_execution_id])
87
+ expect { stores.multi_agent.team_executions.create_active(other) }.to raise_error(Phronomy::AgentBusyError)
88
+ expect(stores.multi_agent.team_executions.list_active(coordination_team.team_id).map(&:team_execution_id)).to eq([coordination_run.team_execution_id])
89
89
  end
90
90
 
91
91
  it "releases admission after terminal CAS while retaining discoverable outcomes" do
92
- persistence.team_executions.create_active(coordination_run)
92
+ stores.multi_agent.team_executions.create_active(coordination_run)
93
93
  completed = coordination_run.with(status: "completed", phase: "completed")
94
- persistence.team_executions.save(coordination_run.team_execution_id, expected_revision: 0, execution: completed)
94
+ stores.multi_agent.team_executions.save(coordination_run.team_execution_id, expected_revision: 0, execution: completed)
95
95
  other = coordination_run.with(team_execution_id: SecureRandom.uuid, execution_revision: 0)
96
- persistence.team_executions.create_active(other)
96
+ stores.multi_agent.team_executions.create_active(other)
97
97
  ids = [completed.team_execution_id, other.team_execution_id].sort
98
- expect(persistence.team_executions.list(coordination_team.team_id, limit: 1).map(&:team_execution_id)).to eq(ids.first(1))
99
- expect(persistence.team_executions.list(coordination_team.team_id, after: ids.first).map(&:team_execution_id)).to eq(ids.last(1))
100
- expect(persistence.team_executions.list("other-team")).to be_empty
98
+ expect(stores.multi_agent.team_executions.list(coordination_team.team_id, limit: 1).map(&:team_execution_id)).to eq(ids.first(1))
99
+ expect(stores.multi_agent.team_executions.list(coordination_team.team_id, after: ids.first).map(&:team_execution_id)).to eq(ids.last(1))
100
+ expect(stores.multi_agent.team_executions.list("other-team")).to be_empty
101
101
  expect do
102
- persistence.team_executions.save(completed.team_execution_id, expected_revision: 0, execution: completed)
102
+ stores.multi_agent.team_executions.save(completed.team_execution_id, expected_revision: 0, execution: completed)
103
103
  end.to raise_error(Phronomy::Persistence::ConflictError)
104
104
  expect do
105
- persistence.team_executions.save(completed.team_execution_id, expected_revision: 1,
105
+ stores.multi_agent.team_executions.save(completed.team_execution_id, expected_revision: 1,
106
106
  execution: completed.with(status: "active", phase: "coordinator"))
107
107
  end.to raise_error(Phronomy::Persistence::ConflictError)
108
108
  end
@@ -112,26 +112,32 @@ RSpec.shared_examples "a Team execution repository" do
112
112
  root_id = "coordination-rollback-agent-#{SecureRandom.uuid}"
113
113
  content_ref = nil
114
114
  expect do
115
- persistence.transaction do |tx|
116
- tx.team_executions.create_active(coordination_run)
117
- tx.teams.save(coordination_team.team_id, expected_revision: 0, root: coordination_team.with(lifecycle_status: "active"))
118
- tx.handoff_states.save(handoff.main_agent_id, expected_revision: nil, state: handoff)
119
- content_ref = tx.contents.put_text("coordination-rollback-#{SecureRandom.uuid}")
120
- root = Phronomy::Agent::AgentRoot.create(agent_id: root_id, agent_definition_id: "rollback", agent_definition_version: 1)
121
- tx.agents.create(root)
122
- tx.journals.append(root_id, expected_position: 0, records: [])
123
- record = Phronomy::Agent::JournalRecord.new(agent_id: root_id, kind: :input_received, channel: :external)
124
- tx.executions.create_active(Phronomy::Agent::AgentExecution.start(agent_root: root, input_record: record))
125
- tx.workflow_states.save(root_id, expected_revision: nil, snapshot: {fields: {value: "committed"}, phase: "pause"})
126
- raise "rollback all eight"
115
+ stores.coordinator.atomic do |scope|
116
+ stores.multi_agent.participate(scope) do |team|
117
+ stores.agent.participate(scope) do |agent|
118
+ scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
119
+ team.team_executions.create_active(coordination_run)
120
+ team.teams.save(coordination_team.team_id, expected_revision: 0, root: coordination_team.with(lifecycle_status: "active"))
121
+ team.handoff_states.save(handoff.main_agent_id, expected_revision: nil, state: handoff)
122
+ content_ref = agent.contents.put_text("coordination-rollback-#{SecureRandom.uuid}")
123
+ root = Phronomy::Agent::AgentRoot.create(agent_id: root_id, agent_definition_id: "rollback", agent_definition_version: 1)
124
+ agent.agents.create(root)
125
+ agent.journals.append(root_id, expected_position: 0, records: [])
126
+ record = Phronomy::Agent::JournalRecord.new(agent_id: root_id, kind: :input_received, channel: :external)
127
+ agent.executions.create_active(Phronomy::Agent::AgentExecution.start(agent_root: root, input_record: record))
128
+ workflow.save(root_id, expected_revision: nil, snapshot: {fields: {value: "committed"}, phase: "pause"})
129
+ raise "rollback all eight"
130
+ end
131
+ end
132
+ end
127
133
  end
128
134
  end.to raise_error(RuntimeError, "rollback all eight")
129
- expect(persistence.teams.load(coordination_team.team_id).team_revision).to eq(0)
130
- expect(persistence.handoff_states.load(handoff.main_agent_id)).to be_nil
131
- expect(persistence.team_executions.list(coordination_team.team_id)).to be_empty
132
- expect { persistence.agents.load(root_id) }.to raise_error(Phronomy::Persistence::NotFoundError)
133
- expect(persistence.executions.list(root_id)).to be_empty
134
- expect(persistence.workflow_states.load(root_id)).to be_nil
135
- expect(persistence.contents.exist?(content_ref)).to be(false)
135
+ expect(stores.multi_agent.teams.load(coordination_team.team_id).team_revision).to eq(0)
136
+ expect(stores.multi_agent.handoff_states.load(handoff.main_agent_id)).to be_nil
137
+ expect(stores.multi_agent.team_executions.list(coordination_team.team_id)).to be_empty
138
+ expect { stores.agent.agents.load(root_id) }.to raise_error(Phronomy::Persistence::NotFoundError)
139
+ expect(stores.agent.executions.list(root_id)).to be_empty
140
+ expect(stores.workflow.load(root_id)).to be_nil
141
+ expect(stores.agent.contents.exist?(content_ref)).to be(false)
136
142
  end
137
143
  end