phronomy 0.27.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 (475) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +52 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +9 -3
  6. data/benchmark/bench_agent_invoke.rb +25 -50
  7. data/benchmark/bench_context_assembler.rb +14 -11
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/benchmark/bench_tool_schema.rb +1 -1
  10. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  11. data/docs/architecture/agent-transition-ownership.md +13 -89
  12. data/docs/architecture/backend-groups.md +152 -0
  13. data/docs/architecture/before-llm-input.md +3 -3
  14. data/docs/architecture/context-management.md +1 -1
  15. data/docs/architecture/execution-abstraction-review.md +88 -0
  16. data/docs/architecture/execution-boundaries.md +28 -0
  17. data/docs/architecture/execution-metadata-and-values.md +6 -0
  18. data/docs/architecture/multi-agent-handoff.md +6 -5
  19. data/docs/architecture/persistence.md +27 -9
  20. data/docs/architecture/r8-unit1.md +104 -0
  21. data/docs/architecture/r8-unit10.md +72 -0
  22. data/docs/architecture/r8-unit11.md +71 -0
  23. data/docs/architecture/r8-unit12.md +67 -0
  24. data/docs/architecture/r8-unit13.md +61 -0
  25. data/docs/architecture/r8-unit14.md +72 -0
  26. data/docs/architecture/r8-unit15.md +65 -0
  27. data/docs/architecture/r8-unit16.md +54 -0
  28. data/docs/architecture/r8-unit17.md +73 -0
  29. data/docs/architecture/r8-unit18.md +92 -0
  30. data/docs/architecture/r8-unit19.md +61 -0
  31. data/docs/architecture/r8-unit2.md +55 -0
  32. data/docs/architecture/r8-unit20.md +51 -0
  33. data/docs/architecture/r8-unit21.md +79 -0
  34. data/docs/architecture/r8-unit22.md +74 -0
  35. data/docs/architecture/r8-unit23.md +81 -0
  36. data/docs/architecture/r8-unit3.md +130 -0
  37. data/docs/architecture/r8-unit4.md +79 -0
  38. data/docs/architecture/r8-unit5.md +115 -0
  39. data/docs/architecture/r8-unit6.md +71 -0
  40. data/docs/architecture/r8-unit7.md +70 -0
  41. data/docs/architecture/r8-unit8.md +78 -0
  42. data/docs/architecture/r8-unit9.md +73 -0
  43. data/docs/architecture/refactoring-closure.md +10 -1
  44. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  45. data/docs/architecture/storage-execution-boundaries.md +54 -0
  46. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  47. data/docs/architecture/tracing.md +1 -1
  48. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  49. data/docs/architecture.md +24 -11
  50. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  51. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  52. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  53. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  54. data/docs/decisions/032-storage-backend-composition.md +5 -0
  55. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  56. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  57. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  58. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  59. data/docs/decisions/040-configuration-default-composition.md +12 -1
  60. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  61. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  62. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  63. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  64. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  65. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  66. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  67. data/docs/decisions/062-content-store-service.md +52 -0
  68. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  69. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  70. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  71. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  72. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  73. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  74. data/docs/decisions/README.md +18 -1
  75. data/docs/execution-boundaries-preview.md +45 -0
  76. data/docs/features.md +8 -3
  77. data/docs/getting-started.md +9 -6
  78. data/docs/migrations/0.22.md +2 -2
  79. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  80. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  81. data/docs/migrations/persistence-failure-contracts.md +67 -0
  82. data/docs/migrations/r8-unit10.md +36 -0
  83. data/docs/migrations/r8-unit11.md +33 -0
  84. data/docs/migrations/r8-unit12.md +31 -0
  85. data/docs/migrations/r8-unit13.md +36 -0
  86. data/docs/migrations/r8-unit14.md +31 -0
  87. data/docs/migrations/r8-unit15.md +31 -0
  88. data/docs/migrations/r8-unit16.md +26 -0
  89. data/docs/migrations/r8-unit17.md +28 -0
  90. data/docs/migrations/r8-unit18.md +29 -0
  91. data/docs/migrations/r8-unit19.md +28 -0
  92. data/docs/migrations/r8-unit20.md +24 -0
  93. data/docs/migrations/r8-unit21.md +28 -0
  94. data/docs/migrations/r8-unit22.md +29 -0
  95. data/docs/migrations/r8-unit23.md +20 -0
  96. data/docs/migrations/r8-unit4.md +67 -0
  97. data/docs/migrations/r8-unit5.md +75 -0
  98. data/docs/migrations/r8-unit6.md +109 -0
  99. data/docs/migrations/r8-unit7.md +31 -0
  100. data/docs/migrations/r8-unit8.md +33 -0
  101. data/docs/migrations/r8-unit9.md +28 -0
  102. data/docs/migrations/storage-async-client.md +103 -0
  103. data/docs/migrations/vector-async-clients.md +110 -0
  104. data/docs/persistence-backends.md +38 -21
  105. data/docs/runtime-and-concurrency.md +26 -1
  106. data/lib/phronomy/agent/admission.rb +78 -0
  107. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  108. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  109. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  110. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  111. data/lib/phronomy/agent/async_event_api.rb +37 -32
  112. data/lib/phronomy/agent/base.rb +74 -72
  113. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  114. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  115. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  116. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  117. data/lib/phronomy/agent/control_request.rb +21 -0
  118. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  119. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  120. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  121. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  122. data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
  123. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  124. data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
  125. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  126. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
  127. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  128. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  129. data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
  130. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  131. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  132. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
  133. data/lib/phronomy/agent/execution_change.rb +161 -0
  134. data/lib/phronomy/agent/execution_environment.rb +36 -0
  135. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  136. data/lib/phronomy/agent/execution_observation.rb +35 -0
  137. data/lib/phronomy/agent/filterable.rb +182 -0
  138. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  139. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  140. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  141. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  142. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  143. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  144. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
  145. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  146. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  147. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  148. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  149. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  150. data/lib/phronomy/agent/persistence/records.rb +33 -0
  151. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  152. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  153. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  154. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  155. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
  156. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
  157. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
  158. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
  159. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  160. data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
  161. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  162. data/lib/phronomy/agent/retention.rb +17 -0
  163. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  164. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  165. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  166. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  167. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  168. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  169. data/lib/phronomy/agent/settings.rb +47 -0
  170. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  171. data/lib/phronomy/agent/store.rb +253 -0
  172. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
  173. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  174. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  175. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  176. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  177. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  178. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  179. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  180. data/lib/phronomy/context/assembly.rb +202 -0
  181. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  182. data/lib/phronomy/context/candidate.rb +51 -0
  183. data/lib/phronomy/context/constraint.rb +47 -0
  184. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  185. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  186. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  187. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  188. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  189. data/lib/phronomy/context/default_policy.rb +140 -0
  190. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  191. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  192. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  193. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  194. data/lib/phronomy/context/manifest_error.rb +10 -0
  195. data/lib/phronomy/context/prompt_template.rb +98 -0
  196. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  197. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  198. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  199. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  200. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  201. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  202. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  203. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  204. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  205. data/lib/phronomy/embeddings/base.rb +43 -0
  206. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  207. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  208. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  209. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  210. data/lib/phronomy/engine/diagnostics.rb +1 -1
  211. data/lib/phronomy/engine/event_loop.rb +7 -7
  212. data/lib/phronomy/engine/execution_binding.rb +23 -0
  213. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  214. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  215. data/lib/phronomy/engine/fsm_session.rb +3 -3
  216. data/lib/phronomy/engine/metrics.rb +16 -14
  217. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  218. data/lib/phronomy/engine/runtime.rb +25 -12
  219. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  220. data/lib/phronomy/execution/async_operation.rb +41 -0
  221. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  222. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  223. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  224. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  225. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  226. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  227. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  228. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  229. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  230. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  231. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  232. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  233. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  234. data/lib/phronomy/execution/runnable.rb +24 -0
  235. data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
  236. data/lib/phronomy/execution/wait_policy.rb +24 -0
  237. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
  238. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  239. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  240. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  241. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  242. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  243. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  244. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  245. data/lib/phronomy/llm_adapter/base.rb +49 -68
  246. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  247. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  248. data/lib/phronomy/llm_adapter/message.rb +62 -0
  249. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  250. data/lib/phronomy/llm_adapter/request.rb +79 -0
  251. data/lib/phronomy/llm_adapter/response.rb +36 -0
  252. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  253. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  254. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  255. data/lib/phronomy/llm_adapter.rb +3 -16
  256. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  257. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  258. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  259. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  260. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  261. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  262. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  263. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  264. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  265. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  266. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  267. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  268. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  269. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  270. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
  271. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  272. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  273. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  274. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  275. data/lib/phronomy/multi_agent/store.rb +156 -0
  276. data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
  277. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  278. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  279. data/lib/phronomy/persistence/content_repository.rb +26 -0
  280. data/lib/phronomy/persistence/errors.rb +16 -0
  281. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  282. data/lib/phronomy/persistence/persistence.rb +23 -0
  283. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  284. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  285. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  286. data/lib/phronomy/persistence/transaction.rb +86 -0
  287. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  288. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  289. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  290. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  291. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  292. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  293. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  294. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  295. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  296. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  297. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  298. data/lib/phronomy/storage/async/async_client.rb +60 -0
  299. data/lib/phronomy/storage/backend.rb +8 -2
  300. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  301. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  302. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  303. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  304. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  305. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  306. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  307. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  308. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  309. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  310. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  311. data/lib/phronomy/tool/authorization.rb +77 -0
  312. data/lib/phronomy/tool/base.rb +549 -9
  313. data/lib/phronomy/tool/call_request.rb +40 -0
  314. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  315. data/lib/phronomy/tool/operation.rb +88 -0
  316. data/lib/phronomy/tool/schema.rb +214 -0
  317. data/lib/phronomy/tool/settings.rb +31 -0
  318. data/lib/phronomy/tool/tool_error.rb +7 -0
  319. data/lib/phronomy/tool/tool_executor.rb +58 -0
  320. data/lib/phronomy/tools/agent.rb +22 -90
  321. data/lib/phronomy/tools/mcp.rb +21 -14
  322. data/lib/phronomy/tools/vector_search.rb +4 -4
  323. data/lib/phronomy/tracing/automatic.rb +11 -6
  324. data/lib/phronomy/tracing/base.rb +1 -1
  325. data/lib/phronomy/tracing/observation.rb +37 -0
  326. data/lib/phronomy/tracing/settings.rb +36 -0
  327. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  328. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  329. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  330. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  331. data/lib/phronomy/vector_store/base.rb +118 -49
  332. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  333. data/lib/phronomy/vector_store.rb +2 -17
  334. data/lib/phronomy/version.rb +1 -1
  335. data/lib/phronomy/workflow/completion.rb +11 -0
  336. data/lib/phronomy/workflow/execution/workflow.rb +7 -7
  337. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  338. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  339. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  340. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
  341. data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
  342. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  343. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  344. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  345. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  346. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  347. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  348. data/lib/phronomy.rb +57 -16
  349. data/scripts/api_snapshot.rb +35 -15
  350. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  351. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  352. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  353. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  354. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  355. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  356. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  357. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  358. data/sig/phronomy/agent/admission.rbs +19 -0
  359. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  360. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  361. data/sig/phronomy/agent/store.rbs +73 -0
  362. data/sig/phronomy/agent.rbs +14 -138
  363. data/sig/phronomy/common.rbs +7 -0
  364. data/sig/phronomy/content_store/contracts.rbs +13 -0
  365. data/sig/phronomy/context.rbs +152 -0
  366. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  367. data/sig/phronomy/embeddings/base.rbs +17 -0
  368. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  369. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  370. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  371. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  372. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  373. data/sig/phronomy/engine/observability.rbs +13 -0
  374. data/sig/phronomy/execution/async_operation.rbs +7 -0
  375. data/sig/phronomy/execution/blocking.rbs +5 -0
  376. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  377. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  378. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  379. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  380. data/sig/phronomy/execution/errors.rbs +7 -0
  381. data/sig/phronomy/execution/execution.rbs +41 -0
  382. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  383. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  384. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  385. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  386. data/sig/phronomy/execution/task_result.rbs +29 -0
  387. data/sig/phronomy/extensions.rbs +0 -21
  388. data/sig/phronomy/handoff.rbs +10 -4
  389. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  390. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  391. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  392. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  393. data/sig/phronomy/llm_context_window.rbs +10 -0
  394. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  395. data/sig/phronomy/multi_agent/store.rbs +54 -0
  396. data/sig/phronomy/multi_agent.rbs +6 -3
  397. data/sig/phronomy/persistence/errors.rbs +18 -0
  398. data/sig/phronomy/persistence/migration.rbs +13 -0
  399. data/sig/phronomy/persistence/transaction.rbs +19 -0
  400. data/sig/phronomy/persistence.rbs +1 -99
  401. data/sig/phronomy/persistence_composition.rbs +19 -0
  402. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  403. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  404. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  405. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
  406. data/sig/phronomy/tool.rbs +48 -4
  407. data/sig/phronomy/tracing/observation.rbs +7 -0
  408. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  409. data/sig/phronomy/vector_store/base.rbs +23 -0
  410. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  411. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  412. data/sig/phronomy/workflow/store.rbs +8 -0
  413. data/sig/phronomy/workflow.rbs +1 -1
  414. data/sig/phronomy.rbs +0 -49
  415. metadata +318 -117
  416. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  417. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  418. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  419. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  420. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  421. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  422. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  423. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  424. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  425. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  426. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  427. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  428. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  429. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  430. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  431. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  432. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  433. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  434. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  435. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  436. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  437. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  438. data/lib/phronomy/configuration/configuration.rb +0 -68
  439. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  440. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  441. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  442. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  443. data/lib/phronomy/engine/runnable.rb +0 -54
  444. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  445. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  446. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  447. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  448. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  449. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  450. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  451. data/lib/phronomy/recovery/recovery.rb +0 -186
  452. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  453. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  454. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  455. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  456. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  457. data/sig/phronomy/execution_receiver.rbs +0 -34
  458. data/sig/phronomy/llm_adapter.rbs +0 -11
  459. data/sig/phronomy/runtime.rbs +0 -76
  460. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  461. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  462. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  463. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  464. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  465. /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
  466. /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
  467. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  468. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  469. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  470. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  471. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  472. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  473. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  474. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  475. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../engine/concurrency/worker_input_restricted"
3
+ require_relative "../../execution/concurrency/worker_input_restricted"
4
4
 
5
5
  module Phronomy
6
6
  module Agent
@@ -20,35 +20,10 @@ module Phronomy
20
20
  )
21
21
  ToolCommand = Data.define(
22
22
  :execution_id, :fsm_session_id, :expected_execution_revision,
23
- :root, :execution, :runtime_snapshot, :tool_batch_snapshot
24
- )
25
- ProviderReconciliationCommand = Data.define(
26
- :operation, :intended_result, :original_error
27
- )
28
- ToolReconciliationCommand = Data.define(
29
- :operation, :intended_result, :original_error
23
+ :root, :execution, :runtime_snapshot, :tool_batch_snapshot, :invocation_config
30
24
  )
31
25
  ProviderResult = Data.define(:execution, :runtime_projection, :error)
32
26
  ToolResult = Data.define(:execution)
33
- ProviderReconciliationResult = Data.define(:disposition, :preparation_result)
34
- ToolReconciliationResult = Data.define(:disposition, :preparation_result)
35
-
36
- # A failed response does not prove that the execution save rolled back.
37
- # @api private
38
- class OutcomeUnknownError < Phronomy::Error
39
- attr_reader :original_error, :intended_result
40
-
41
- def initialize(original_error, intended_result)
42
- @original_error = original_error
43
- @intended_result = intended_result
44
- super(
45
- "durable dispatch preparation outcome is uncertain: " \
46
- "#{original_error.class}: #{original_error.message}"
47
- )
48
- set_backtrace(original_error.backtrace)
49
- end
50
- end
51
-
52
27
  # @api private
53
28
  def initialize(agent:, persistence:)
54
29
  @agent = agent
@@ -68,47 +43,13 @@ module Phronomy
68
43
 
69
44
  # @api private
70
45
  def prepare_tools(operation)
71
- intended = nil
72
- begin
73
- @persistence.transaction do |tx|
74
- assert_local_durable_base!(tx, operation.root)
75
- updated = build_tool_dispatch_execution(operation, tx)
76
- updated = @agent.__prepare_coordination_record(updated, tx: tx)
77
- tx.executions.save(
78
- operation.execution.execution_id,
79
- expected_revision: operation.execution.execution_revision,
80
- execution: updated
81
- )
82
- intended = ToolResult.new(execution: updated)
83
- end
84
- rescue => caught
85
- raise if known_durable_failure?(caught) || intended.nil?
86
-
87
- raise OutcomeUnknownError.new(caught, intended)
46
+ updated = @persistence.transaction do |tx|
47
+ assert_local_durable_base!(tx, operation.root)
48
+ build_tool_dispatch_execution(operation, tx)
88
49
  end
89
- intended
90
- end
91
-
92
- # @api private
93
- def reconcile_provider(command)
94
- disposition, current = reconcile_preparation(
95
- command.operation, command.intended_result.execution
96
- )
97
- result = restore_provider_result(current) if disposition == :committed
98
- ProviderReconciliationResult.new(
99
- disposition: disposition, preparation_result: result
100
- )
101
- end
102
-
103
- # @api private
104
- def reconcile_tools(command)
105
- disposition, current = reconcile_preparation(
106
- command.operation, command.intended_result.execution
107
- )
108
- result = ToolResult.new(execution: current) if disposition == :committed
109
- ToolReconciliationResult.new(
110
- disposition: disposition, preparation_result: result
111
- )
50
+ change = ExecutionChange.new(agent: @agent, current: operation.execution,
51
+ root: operation.root, kind: :dispatch, updated: updated, config: operation.invocation_config)
52
+ ToolResult.new(execution: change.perform)
112
53
  end
113
54
 
114
55
  private
@@ -154,7 +95,7 @@ module Phronomy
154
95
  call_sequence: recorded.llm_calls.length + 1,
155
96
  config: operation.invocation_config
156
97
  )
157
- assembler = ContextAssembler.new(
98
+ assembler = ContextPreparation.new(
158
99
  agent: @agent,
159
100
  persistence: @persistence,
160
101
  journal_records: operation.journal_records
@@ -175,27 +116,14 @@ module Phronomy
175
116
  end
176
117
 
177
118
  def commit_provider_preparation(operation, recorded, assembler, prepared)
178
- manifest = manifest_ref = intended = nil
179
- begin
180
- @persistence.transaction do |tx|
181
- assert_local_durable_base!(tx, operation.root)
182
- manifest, manifest_ref = assembler.finalize(prepared, persistence: tx)
183
- updated = execution_with_provider_manifest(recorded, manifest_ref)
184
- updated = @agent.__prepare_coordination_record(updated, tx: tx)
185
- tx.executions.save(
186
- operation.execution.execution_id,
187
- expected_revision: operation.execution.execution_revision,
188
- execution: updated
189
- )
190
- intended = ProviderResult.new(
191
- execution: updated, runtime_projection: nil, error: nil
192
- )
193
- end
194
- rescue => caught
195
- raise if known_durable_failure?(caught) || intended.nil?
196
-
197
- raise OutcomeUnknownError.new(caught, intended)
119
+ manifest, manifest_ref = @persistence.transaction do |tx|
120
+ assert_local_durable_base!(tx, operation.root)
121
+ Phronomy::Context::Assembly.new.store(prepared, contents: tx.contents)
198
122
  end
123
+ updated = execution_with_provider_manifest(recorded, manifest_ref)
124
+ change = ExecutionChange.new(agent: @agent, current: operation.execution,
125
+ root: operation.root, kind: :dispatch, updated: updated, config: operation.invocation_config)
126
+ intended = ProviderResult.new(execution: change.perform, runtime_projection: nil, error: nil)
199
127
  [intended, manifest, manifest_ref]
200
128
  end
201
129
 
@@ -213,7 +141,7 @@ module Phronomy
213
141
  def materialize_provider_result(execution, manifest, manifest_ref)
214
142
  projection = materialization_error = nil
215
143
  begin
216
- projection = RubyLLMMaterializer.new(
144
+ projection = RuntimeInput.new(
217
145
  agent: @agent, persistence: @persistence
218
146
  ).materialize(manifest: manifest, manifest_ref: manifest_ref)
219
147
  rescue => error
@@ -225,21 +153,6 @@ module Phronomy
225
153
  )
226
154
  end
227
155
 
228
- def restore_provider_result(execution)
229
- projection = materialization_error = nil
230
- begin
231
- _manifest, projection = SavedContextReader.materialize_projection(
232
- @agent, execution.metadata.fetch("manifest_ref")
233
- )
234
- rescue => error
235
- materialization_error = error
236
- end
237
- ProviderResult.new(
238
- execution: execution, runtime_projection: projection,
239
- error: materialization_error
240
- )
241
- end
242
-
243
156
  def build_tool_dispatch_execution(operation, tx)
244
157
  encoded_records, call_records = RuntimeRecordEncoder.encode(
245
158
  operation.execution,
@@ -270,29 +183,6 @@ module Phronomy
270
183
  metadata
271
184
  end
272
185
 
273
- def reconcile_preparation(operation, intended_execution)
274
- current = @persistence.executions.load(operation.execution_id)
275
- if current.execution_revision == intended_execution.execution_revision &&
276
- current.to_h == intended_execution.to_h
277
- return [:committed, current]
278
- end
279
- if current.execution_revision == operation.execution.execution_revision &&
280
- current.to_h == operation.execution.to_h
281
- return [:not_committed, current]
282
- end
283
-
284
- [:conflict, current]
285
- end
286
-
287
- def known_durable_failure?(error)
288
- error.is_a?(Phronomy::Storage::ConflictError) ||
289
- error.is_a?(Phronomy::Storage::NotFoundError) ||
290
- error.is_a?(Phronomy::Storage::SerializationError) ||
291
- error.is_a?(Phronomy::Storage::UnsupportedBackendError) ||
292
- error.is_a?(ArgumentError) ||
293
- error.is_a?(Phronomy::ConfigurationError)
294
- end
295
-
296
186
  def assert_local_durable_base!(tx, root)
297
187
  tx.assert_agent_watermark!(
298
188
  agent_id: root.agent_id,
@@ -10,24 +10,25 @@ module Phronomy
10
10
  Wait = Data.define(:coordinator, :agent, :execution_id)
11
11
  private_constant :Wait
12
12
 
13
- def self.start(agent:, execution_id:, input:, config: {})
14
- new(agent, execution_id, input, config).start
13
+ def self.start(agent:, execution_id:, input:, config: {}, resume_only: false)
14
+ new(agent, execution_id, input, config, resume_only).start
15
15
  end
16
16
 
17
- def initialize(agent, execution_id, input, config)
17
+ def initialize(agent, execution_id, input, config, resume_only)
18
18
  @agent, @id, @input, @config = agent, execution_id.to_s.freeze, input, config.freeze
19
- @runtime = Phronomy::Runtime.instance
19
+ @resume_only = resume_only
20
+ @environment = @agent.__execution_environment
20
21
  @completion = Phronomy::TaskResult.deferred(name: "exact-execution:#{@id}")
21
22
  end
22
23
 
23
24
  def start
24
- preparation = @runtime.offload.submit(on_full: :raise) do
25
+ preparation = @environment.submit(on_full: :raise) do
25
26
  execution = read_execution
26
27
  if execution&.terminal?
27
28
  [:terminal, materialize(execution)]
28
29
  elsif execution
29
- unless Phronomy::Agent::ExecutionRegistry.existing_for(@runtime)&.agent_execution_owner(@id)
30
- @agent.instance_variable_set(:@_phronomy_coordination_config, @config)
30
+ unless @environment.existing_registry&.agent_execution_owner(@id)
31
+ @agent.instance_variable_set(:@_phronomy_execution_wiring, @config)
31
32
  begin
32
33
  RecoveryCoordinator.new(@agent).recover_on_load!
33
34
  rescue Phronomy::ConfigurationError => error
@@ -37,6 +38,7 @@ module Phronomy
37
38
  end
38
39
  [:active, nil]
39
40
  else
41
+ raise Phronomy::Persistence::NotFoundError, "Execution #{@id} is absent" if @resume_only
40
42
  @config[:cancellation_token]&.raise_if_cancelled!
41
43
  [:absent, nil]
42
44
  end
@@ -55,7 +57,7 @@ module Phronomy
55
57
  source.on_complete { |_value, failure| reconcile(failure) }
56
58
  when :active
57
59
  command = Wait.new(coordinator: self, agent: @agent, execution_id: @id)
58
- posted = ExecutionRegistry.for(@runtime.event_loop).post(command, completion: @completion)
60
+ posted = @environment.registry.post(command, completion: @completion)
59
61
  @completion.fail(Phronomy::RuntimeShutdownError.new("Exact execution observer rejected")) unless posted
60
62
  end
61
63
  end
@@ -69,7 +71,7 @@ module Phronomy
69
71
  end
70
72
 
71
73
  def deliver_on_event_loop(command)
72
- state = Phronomy::Agent::ExecutionRegistry.for(@runtime.event_loop).agent_execution_state(command.execution_id)
74
+ state = @environment.registry.agent_execution_state(command.execution_id)
73
75
  unless state
74
76
  # Ownership can be released between the durable read and this command.
75
77
  # Reinstall once with the caller's current wiring/cancellation request.
@@ -80,9 +82,13 @@ module Phronomy
80
82
  return reconcile(nil)
81
83
  end
82
84
  unless state.agent.equal?(command.agent)
83
- raise Phronomy::Storage::ConflictError, "Exact execution #{@id} owner mismatch"
85
+ raise Phronomy::Persistence::StateConflictError, "Exact execution #{@id} owner mismatch"
84
86
  end
85
87
  if @config[:cancellation_token]&.cancelled?
88
+ # One observation governs both recording and notification. A newly
89
+ # observed request must be persisted off EventLoop before signaling.
90
+ return start unless @cancellation_recorded
91
+
86
92
  state.invocation&.config&.fetch(:cancellation_token, nil)&.cancel!
87
93
  end
88
94
  if state.execution.status == :suspended || state.fsm_session_id.nil?
@@ -93,7 +99,7 @@ module Phronomy
93
99
  state.invocation.merge_config!(phronomy_exact_observers: (observers + [@completion]).uniq.freeze)
94
100
  waiter = Phronomy::TaskResult.deferred(name: "exact-wait:#{@id}")
95
101
  waiter.on_complete { |_result, failure| reconcile(failure) }
96
- Phronomy::Agent::ExecutionRegistry.for(@runtime.event_loop).register_agent_completion_waiter(@id, waiter)
102
+ @environment.registry.register_agent_completion_waiter(@id, waiter)
97
103
  rescue => failure
98
104
  @completion.fail(failure)
99
105
  end
@@ -103,30 +109,45 @@ module Phronomy
103
109
  def read_execution
104
110
  begin
105
111
  execution = @agent.persistence.executions.load(@id)
106
- rescue Phronomy::Storage::NotFoundError
112
+ rescue Phronomy::Persistence::NotFoundError
107
113
  return nil
108
114
  end
109
115
  unless execution.agent_id == @agent.agent_id
110
- raise Phronomy::Storage::ConflictError, "Reserved execution #{@id} belongs to another Agent"
116
+ raise Phronomy::Persistence::StateConflictError, "Reserved execution #{@id} belongs to another Agent"
111
117
  end
112
- expected = @config[:phronomy_coordination]
113
- stored = execution.metadata["coordination"]
118
+ expected = @config[:phronomy_reservation]
119
+ stored = execution.metadata["reservation"]
114
120
  if expected && stored != expected
115
- actual_identity = stored&.except("handoff_revision")
116
- expected_identity = expected.except("handoff_revision")
117
- unless actual_identity == expected_identity
118
- raise Phronomy::Storage::ConflictError, "Reserved execution #{@id} coordination mismatch"
119
- end
121
+ raise Phronomy::Persistence::StateConflictError, "Reserved execution #{@id} correlation mismatch"
120
122
  end
121
123
  ref = execution.metadata["current_input_ref"]
124
+ @input = @agent.persistence.contents.fetch_text(ref) if @resume_only && ref
122
125
  if ref && @agent.persistence.contents.fetch_text(ref) != @input
123
- raise Phronomy::Storage::ConflictError, "Reserved execution #{@id} input mismatch"
126
+ raise Phronomy::Persistence::StateConflictError, "Reserved execution #{@id} input mismatch"
127
+ end
128
+ unless execution.terminal?
129
+ extension = execution.metadata["execution_extension"]
130
+ participant = @config[:phronomy_execution_participant]
131
+ if extension && (!participant || participant.binding.to_h.except("state_ref") != extension.except("state_ref"))
132
+ raise Phronomy::ExecutionRehydrationRequiredError, "Execution #{@id} needs its current participant binding"
133
+ end
134
+ # The ledger is independent of execution revision, so recording intent
135
+ # does not invalidate an already captured outcome command.
136
+ if @config[:cancellation_token]&.cancelled?
137
+ @cancellation_recorded = @agent.persistence.request_cancellation(agent_id: @agent.agent_id, execution_id: @id)
138
+ end
139
+ if @agent.persistence.cancellation_requested?(agent_id: @agent.agent_id, execution_id: @id)
140
+ @cancellation_recorded = true
141
+ token = @config[:cancellation_token] || Phronomy::Concurrency::CancellationToken.new
142
+ token.cancel!
143
+ @config = @config.merge(cancellation_token: token).freeze
144
+ end
124
145
  end
125
146
  execution
126
147
  end
127
148
 
128
149
  def reconcile(failure)
129
- task = @runtime.offload.submit(on_full: :raise) do
150
+ task = @environment.submit(on_full: :raise) do
130
151
  execution = read_execution
131
152
  if execution&.terminal?
132
153
  materialize(execution)
@@ -144,7 +165,7 @@ module Phronomy
144
165
  end
145
166
 
146
167
  def materialize(execution)
147
- result = @agent.persistence.execution_result(execution.execution_id)
168
+ result = @agent.persistence.result(execution.execution_id)
148
169
  result.merge(output: result[:result]).freeze
149
170
  end
150
171
  end
@@ -9,13 +9,17 @@ module Phronomy
9
9
  Command = Data.define(:coordinator, :execution_id, :agent_id)
10
10
  private_constant :Command
11
11
 
12
- def self.signal(execution_id, agent_id)
13
- command = Command.new(coordinator: new, execution_id: execution_id, agent_id: agent_id)
14
- ExecutionRegistry.for(Phronomy::Runtime.instance.event_loop).post(command)
12
+ def self.signal(execution_id, agent_id, environment:)
13
+ command = Command.new(coordinator: new(environment), execution_id: execution_id, agent_id: agent_id)
14
+ environment.registry.post(command)
15
+ end
16
+
17
+ def initialize(environment)
18
+ @environment = environment
15
19
  end
16
20
 
17
21
  def deliver_on_event_loop(command)
18
- state = Phronomy::Agent::ExecutionRegistry.for(Phronomy::Runtime.instance.event_loop).agent_execution_state(command.execution_id)
22
+ state = @environment.registry.agent_execution_state(command.execution_id)
19
23
  return unless state && state.agent.agent_id == command.agent_id
20
24
  state.invocation&.config&.fetch(:cancellation_token, nil)&.cancel!
21
25
  end