phronomy 0.27.0 → 0.29.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 (517) 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 +28 -7
  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/application-recipes.md +229 -0
  11. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  12. data/docs/architecture/agent-transition-ownership.md +13 -89
  13. data/docs/architecture/backend-groups.md +152 -0
  14. data/docs/architecture/before-llm-input.md +3 -3
  15. data/docs/architecture/context-management.md +1 -1
  16. data/docs/architecture/dx05-agent-scope.md +119 -0
  17. data/docs/architecture/dx05-workflow-task-state.md +134 -0
  18. data/docs/architecture/error-api-review.md +245 -0
  19. data/docs/architecture/execution-abstraction-review.md +88 -0
  20. data/docs/architecture/execution-boundaries.md +28 -0
  21. data/docs/architecture/execution-metadata-and-values.md +6 -0
  22. data/docs/architecture/multi-agent-handoff.md +6 -5
  23. data/docs/architecture/persistence.md +27 -9
  24. data/docs/architecture/r8-unit1.md +104 -0
  25. data/docs/architecture/r8-unit10.md +72 -0
  26. data/docs/architecture/r8-unit11.md +71 -0
  27. data/docs/architecture/r8-unit12.md +67 -0
  28. data/docs/architecture/r8-unit13.md +61 -0
  29. data/docs/architecture/r8-unit14.md +72 -0
  30. data/docs/architecture/r8-unit15.md +65 -0
  31. data/docs/architecture/r8-unit16.md +54 -0
  32. data/docs/architecture/r8-unit17.md +73 -0
  33. data/docs/architecture/r8-unit18.md +92 -0
  34. data/docs/architecture/r8-unit19.md +61 -0
  35. data/docs/architecture/r8-unit2.md +55 -0
  36. data/docs/architecture/r8-unit20.md +51 -0
  37. data/docs/architecture/r8-unit21.md +79 -0
  38. data/docs/architecture/r8-unit22.md +74 -0
  39. data/docs/architecture/r8-unit23.md +81 -0
  40. data/docs/architecture/r8-unit3.md +130 -0
  41. data/docs/architecture/r8-unit4.md +79 -0
  42. data/docs/architecture/r8-unit5.md +115 -0
  43. data/docs/architecture/r8-unit6.md +71 -0
  44. data/docs/architecture/r8-unit7.md +70 -0
  45. data/docs/architecture/r8-unit8.md +78 -0
  46. data/docs/architecture/r8-unit9.md +73 -0
  47. data/docs/architecture/refactoring-closure.md +10 -1
  48. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  49. data/docs/architecture/storage-execution-boundaries.md +54 -0
  50. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  51. data/docs/architecture/tracing.md +1 -1
  52. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  53. data/docs/architecture.md +24 -11
  54. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  55. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  56. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  57. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  58. data/docs/decisions/032-storage-backend-composition.md +5 -0
  59. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  60. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  61. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  62. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  63. data/docs/decisions/040-configuration-default-composition.md +12 -1
  64. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  65. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  66. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  67. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  68. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  69. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  70. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  71. data/docs/decisions/062-content-store-service.md +52 -0
  72. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  73. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  74. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  75. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  76. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  77. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  78. data/docs/decisions/README.md +18 -1
  79. data/docs/execution-boundaries-preview.md +45 -0
  80. data/docs/failure-reason-codes.md +45 -0
  81. data/docs/features.md +12 -4
  82. data/docs/getting-started.md +52 -48
  83. data/docs/migrations/0.22.md +2 -2
  84. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  85. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  86. data/docs/migrations/persistence-failure-contracts.md +67 -0
  87. data/docs/migrations/r8-unit10.md +36 -0
  88. data/docs/migrations/r8-unit11.md +33 -0
  89. data/docs/migrations/r8-unit12.md +31 -0
  90. data/docs/migrations/r8-unit13.md +36 -0
  91. data/docs/migrations/r8-unit14.md +31 -0
  92. data/docs/migrations/r8-unit15.md +31 -0
  93. data/docs/migrations/r8-unit16.md +26 -0
  94. data/docs/migrations/r8-unit17.md +28 -0
  95. data/docs/migrations/r8-unit18.md +29 -0
  96. data/docs/migrations/r8-unit19.md +28 -0
  97. data/docs/migrations/r8-unit20.md +24 -0
  98. data/docs/migrations/r8-unit21.md +28 -0
  99. data/docs/migrations/r8-unit22.md +29 -0
  100. data/docs/migrations/r8-unit23.md +20 -0
  101. data/docs/migrations/r8-unit4.md +67 -0
  102. data/docs/migrations/r8-unit5.md +75 -0
  103. data/docs/migrations/r8-unit6.md +109 -0
  104. data/docs/migrations/r8-unit7.md +31 -0
  105. data/docs/migrations/r8-unit8.md +33 -0
  106. data/docs/migrations/r8-unit9.md +28 -0
  107. data/docs/migrations/storage-async-client.md +103 -0
  108. data/docs/migrations/vector-async-clients.md +110 -0
  109. data/docs/ordered-event-delivery.md +54 -0
  110. data/docs/persistence-backends.md +38 -21
  111. data/docs/runtime-and-concurrency.md +26 -1
  112. data/docs/workflow-completion.md +92 -0
  113. data/gemfiles/http_minimum.gemfile +5 -0
  114. data/lib/phronomy/agent/admission.rb +78 -0
  115. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  116. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  117. data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
  118. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  119. data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
  120. data/lib/phronomy/agent/api/agent.rb +13 -0
  121. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  122. data/lib/phronomy/agent/async_event_api.rb +132 -103
  123. data/lib/phronomy/agent/base.rb +146 -113
  124. data/lib/phronomy/agent/before_llm_input.rb +70 -0
  125. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  126. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  127. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  128. data/lib/phronomy/agent/control_request.rb +21 -0
  129. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  130. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  131. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  132. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  133. data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
  134. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  135. data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
  136. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  137. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
  138. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  139. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  140. data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
  141. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  142. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  143. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
  144. data/lib/phronomy/agent/execution_change.rb +161 -0
  145. data/lib/phronomy/agent/execution_environment.rb +36 -0
  146. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  147. data/lib/phronomy/agent/execution_observation.rb +35 -0
  148. data/lib/phronomy/agent/filterable.rb +188 -0
  149. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  150. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  151. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  152. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  153. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  154. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  155. data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
  156. data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
  157. data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
  158. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
  159. data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
  160. data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
  161. data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
  162. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  163. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  164. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  165. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  166. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  167. data/lib/phronomy/agent/persistence/records.rb +33 -0
  168. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  169. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  170. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  171. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  172. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
  173. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
  174. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
  175. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
  176. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  177. data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
  178. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  179. data/lib/phronomy/agent/retention.rb +17 -0
  180. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  181. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  182. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  183. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  184. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  185. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  186. data/lib/phronomy/agent/settings.rb +47 -0
  187. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  188. data/lib/phronomy/agent/store.rb +253 -0
  189. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
  190. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  191. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  192. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  193. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  194. data/lib/phronomy/common/error.rb +65 -1
  195. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  196. data/lib/phronomy/content_store/base.rb +7 -2
  197. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  198. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  199. data/lib/phronomy/context/assembly.rb +195 -0
  200. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  201. data/lib/phronomy/context/candidate.rb +51 -0
  202. data/lib/phronomy/context/constraint.rb +47 -0
  203. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  204. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  205. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  206. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  207. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  208. data/lib/phronomy/context/default_policy.rb +140 -0
  209. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  210. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  211. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  212. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  213. data/lib/phronomy/context/manifest_error.rb +10 -0
  214. data/lib/phronomy/context/prompt_template.rb +98 -0
  215. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  216. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  217. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  218. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  219. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  220. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  221. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  222. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  223. data/lib/phronomy/embeddings/authentication_error.rb +11 -0
  224. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
  225. data/lib/phronomy/embeddings/base.rb +43 -0
  226. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  227. data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
  228. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  229. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  230. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  231. data/lib/phronomy/engine/diagnostics.rb +1 -1
  232. data/lib/phronomy/engine/event_loop.rb +7 -7
  233. data/lib/phronomy/engine/execution_binding.rb +23 -0
  234. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  235. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  236. data/lib/phronomy/engine/fsm_session.rb +3 -3
  237. data/lib/phronomy/engine/metrics.rb +16 -14
  238. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  239. data/lib/phronomy/engine/runtime.rb +25 -12
  240. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  241. data/lib/phronomy/execution/async_operation.rb +41 -0
  242. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  243. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  244. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  245. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  246. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  247. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  248. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  249. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  250. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  251. data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
  252. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  253. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  254. data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
  255. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  256. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  257. data/lib/phronomy/execution/runnable.rb +24 -0
  258. data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
  259. data/lib/phronomy/execution/wait_policy.rb +24 -0
  260. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
  261. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  262. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  263. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  264. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  265. data/lib/phronomy/generation/low_confidence_error.rb +2 -2
  266. data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
  267. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  268. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  269. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  270. data/lib/phronomy/llm_adapter/base.rb +49 -68
  271. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  272. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  273. data/lib/phronomy/llm_adapter/message.rb +62 -0
  274. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  275. data/lib/phronomy/llm_adapter/request.rb +79 -0
  276. data/lib/phronomy/llm_adapter/response.rb +36 -0
  277. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  278. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  279. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  280. data/lib/phronomy/llm_adapter.rb +3 -16
  281. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  282. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  283. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  284. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  285. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  286. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  287. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  288. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  289. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  290. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  291. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  292. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  293. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  294. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  295. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +60 -44
  296. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  297. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  298. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  299. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  300. data/lib/phronomy/multi_agent/store.rb +156 -0
  301. data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
  302. data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
  303. data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
  304. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  305. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  306. data/lib/phronomy/persistence/content_repository.rb +26 -0
  307. data/lib/phronomy/persistence/errors.rb +16 -0
  308. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  309. data/lib/phronomy/persistence/persistence.rb +23 -0
  310. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  311. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  312. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  313. data/lib/phronomy/persistence/transaction.rb +86 -0
  314. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  315. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  316. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  317. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  318. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  319. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  320. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  321. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  322. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  323. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  324. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  325. data/lib/phronomy/storage/async/async_client.rb +60 -0
  326. data/lib/phronomy/storage/backend.rb +8 -2
  327. data/lib/phronomy/storage/condition_failed_error.rb +2 -2
  328. data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
  329. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  330. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  331. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  332. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  333. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  334. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  335. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  336. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  337. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  338. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  339. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  340. data/lib/phronomy/tool/authorization.rb +77 -0
  341. data/lib/phronomy/tool/base.rb +551 -9
  342. data/lib/phronomy/tool/call_request.rb +40 -0
  343. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  344. data/lib/phronomy/tool/operation.rb +88 -0
  345. data/lib/phronomy/tool/schema.rb +214 -0
  346. data/lib/phronomy/tool/settings.rb +31 -0
  347. data/lib/phronomy/tool/tool_error.rb +7 -0
  348. data/lib/phronomy/tool/tool_executor.rb +58 -0
  349. data/lib/phronomy/tools/agent.rb +22 -90
  350. data/lib/phronomy/tools/mcp.rb +21 -14
  351. data/lib/phronomy/tools/vector_search.rb +4 -4
  352. data/lib/phronomy/tracing/automatic.rb +11 -6
  353. data/lib/phronomy/tracing/base.rb +36 -7
  354. data/lib/phronomy/tracing/observation.rb +37 -0
  355. data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
  356. data/lib/phronomy/tracing/settings.rb +36 -0
  357. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  358. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  359. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  360. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  361. data/lib/phronomy/vector_store/base.rb +118 -49
  362. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  363. data/lib/phronomy/vector_store.rb +2 -17
  364. data/lib/phronomy/version.rb +1 -1
  365. data/lib/phronomy/workflow/completion.rb +11 -0
  366. data/lib/phronomy/workflow/execution/workflow.rb +37 -9
  367. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  368. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  369. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
  370. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
  371. data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
  372. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  373. data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
  374. data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
  375. data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
  376. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  377. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  378. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
  379. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
  380. data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
  381. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  382. data/lib/phronomy.rb +63 -16
  383. data/scripts/api_snapshot.rb +47 -15
  384. data/scripts/check_readme_ruby.rb +24 -29
  385. data/scripts/check_readme_runnable.rb +92 -81
  386. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  387. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  388. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  389. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  390. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  391. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  392. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  393. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  394. data/sig/phronomy/agent/admission.rbs +19 -0
  395. data/sig/phronomy/agent/agent_not_found_error.rbs +6 -0
  396. data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -0
  397. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  398. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  399. data/sig/phronomy/agent/store.rbs +73 -0
  400. data/sig/phronomy/agent/stream_callback_error.rbs +8 -0
  401. data/sig/phronomy/agent.rbs +29 -135
  402. data/sig/phronomy/common.rbs +7 -0
  403. data/sig/phronomy/content_store/contracts.rbs +13 -0
  404. data/sig/phronomy/context.rbs +152 -0
  405. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  406. data/sig/phronomy/embeddings/base.rbs +23 -0
  407. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  408. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  409. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  410. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  411. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  412. data/sig/phronomy/engine/observability.rbs +13 -0
  413. data/sig/phronomy/execution/async_operation.rbs +7 -0
  414. data/sig/phronomy/execution/blocking.rbs +5 -0
  415. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  416. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  417. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  418. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  419. data/sig/phronomy/execution/errors.rbs +7 -0
  420. data/sig/phronomy/execution/execution.rbs +41 -0
  421. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  422. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  423. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  424. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  425. data/sig/phronomy/execution/task_result.rbs +29 -0
  426. data/sig/phronomy/extensions.rbs +1 -21
  427. data/sig/phronomy/filter/filter_block_error.rbs +6 -0
  428. data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
  429. data/sig/phronomy/handoff.rbs +10 -4
  430. data/sig/phronomy/integrations.rbs +14 -0
  431. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  432. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  433. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  434. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  435. data/sig/phronomy/llm_context_window.rbs +10 -0
  436. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  437. data/sig/phronomy/multi_agent/store.rbs +54 -0
  438. data/sig/phronomy/multi_agent/team_busy_error.rbs +8 -0
  439. data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
  440. data/sig/phronomy/multi_agent.rbs +6 -3
  441. data/sig/phronomy/persistence/errors.rbs +18 -0
  442. data/sig/phronomy/persistence/migration.rbs +13 -0
  443. data/sig/phronomy/persistence/transaction.rbs +19 -0
  444. data/sig/phronomy/persistence.rbs +1 -99
  445. data/sig/phronomy/persistence_composition.rbs +19 -0
  446. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  447. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  448. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  449. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +4 -18
  450. data/sig/phronomy/tool.rbs +48 -4
  451. data/sig/phronomy/tracing/observation.rbs +7 -0
  452. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  453. data/sig/phronomy/vector_store/base.rbs +23 -0
  454. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +15 -0
  455. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  456. data/sig/phronomy/workflow/store.rbs +8 -0
  457. data/sig/phronomy/workflow.rbs +5 -1
  458. data/sig/phronomy.rbs +4 -49
  459. metadata +365 -117
  460. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  461. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  462. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  463. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  464. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  465. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  466. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  467. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  468. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  469. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  470. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  471. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  472. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  473. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  474. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  475. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  476. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  477. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  478. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  479. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  480. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  481. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  482. data/lib/phronomy/configuration/configuration.rb +0 -68
  483. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  484. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  485. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  486. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  487. data/lib/phronomy/engine/runnable.rb +0 -54
  488. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  489. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  490. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  491. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  492. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  493. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  494. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  495. data/lib/phronomy/recovery/recovery.rb +0 -186
  496. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  497. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  498. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  499. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  500. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  501. data/sig/phronomy/execution_receiver.rbs +0 -34
  502. data/sig/phronomy/llm_adapter.rbs +0 -11
  503. data/sig/phronomy/runtime.rbs +0 -76
  504. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  505. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  506. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  507. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  508. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  509. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  510. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  511. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  512. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  513. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  514. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  515. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  516. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  517. /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
  require "time"
6
6
  require "securerandom"
@@ -14,7 +14,7 @@ module Phronomy
14
14
  StartCommand = Data.define(
15
15
  :coordinator, :input, :config, :mode,
16
16
  :approval_policy, :approval_listener, :on_event, :result_task,
17
- :admission_token
17
+ :admission_token, :controls
18
18
  )
19
19
  ResumeCommand = Data.define(
20
20
  :coordinator, :execution_id, :approval_request_id,
@@ -39,10 +39,7 @@ module Phronomy
39
39
  InitialPreparationCommand = InitialPreparation::Command
40
40
  ProviderDispatchPreparationCommand = DispatchPreparation::ProviderCommand
41
41
  ToolDispatchPreparationCommand = DispatchPreparation::ToolCommand
42
- ProviderDispatchPreparationReconciliationCommand = DispatchPreparation::ProviderReconciliationCommand
43
- ToolDispatchPreparationReconciliationCommand = DispatchPreparation::ToolReconciliationCommand
44
42
  ResumeCommitCommand = ApprovalResumeCommit::Command
45
- HandoffTerminalView = ExecutionOutcomeCommitter::HandoffTerminalView
46
43
  TerminalView = ExecutionOutcomeCommitter::TerminalView
47
44
  TerminalCommitCommand = ExecutionOutcomeCommitter::Command
48
45
  TerminalDelivery = Data.define(
@@ -55,8 +52,6 @@ module Phronomy
55
52
  InitialPreparationResult = InitialPreparation::Result
56
53
  ProviderDispatchPreparationResult = DispatchPreparation::ProviderResult
57
54
  ToolDispatchPreparationResult = DispatchPreparation::ToolResult
58
- ProviderDispatchPreparationReconciliationResult = DispatchPreparation::ProviderReconciliationResult
59
- ToolDispatchPreparationReconciliationResult = DispatchPreparation::ToolReconciliationResult
60
55
  ResumeCommitResult = ApprovalResumeCommit::Result
61
56
  TerminalOutcome = ExecutionOutcomeCommitter::Outcome
62
57
 
@@ -73,12 +68,6 @@ module Phronomy
73
68
  ToolDispatchPreparationReady = Data.define(
74
69
  :coordinator, :operation, :result, :error
75
70
  )
76
- ProviderDispatchPreparationReconciliationReady = Data.define(
77
- :coordinator, :command, :result, :error
78
- )
79
- ToolDispatchPreparationReconciliationReady = Data.define(
80
- :coordinator, :command, :result, :error
81
- )
82
71
  ResumeCommitReady = Data.define(
83
72
  :coordinator, :request, :operation, :result, :error
84
73
  )
@@ -90,9 +79,6 @@ module Phronomy
90
79
  :source_error, :fsm_session_id
91
80
  )
92
81
 
93
- PreparationOutcomeUnknownError = DispatchPreparation::OutcomeUnknownError
94
- private_constant :PreparationOutcomeUnknownError
95
-
96
82
  def initialize(agent)
97
83
  @agent = agent
98
84
  @initial_preparation = InitialPreparation.new(agent: agent, persistence: agent.persistence)
@@ -107,15 +93,11 @@ module Phronomy
107
93
  )
108
94
  @agent.send(:__assert_live_agent!)
109
95
  @agent.send(:_reject_removed_generic_identity_keys!, config)
110
- result_task = Phronomy::TaskResult.deferred(name: "agent-#{@agent.agent_id}-#{mode}")
111
- if config[:invocation_context]
112
- binding = Phronomy::Concurrency::OperationBinding.new(
113
- invocation_context: config[:invocation_context],
114
- cancellation_token: config[:cancellation_token]
115
- )
116
- binding.bind(result_task)
117
- config = config.merge(cancellation_token: binding.token)
118
- end
96
+ result_task = OperationResult.new(agent: @agent, name: "agent-#{@agent.agent_id}-#{mode}")
97
+ controls = Phronomy::InvocationControls.attach(result_task,
98
+ invocation_context: config[:invocation_context],
99
+ cancellation_token: config[:cancellation_token])
100
+ config = config.merge(cancellation_token: controls.token)
119
101
  command = StartCommand.new(
120
102
  coordinator: self,
121
103
  input: input,
@@ -125,14 +107,15 @@ module Phronomy
125
107
  approval_listener: approval_listener,
126
108
  on_event: on_event,
127
109
  result_task: result_task,
128
- admission_token: Object.new.freeze
110
+ admission_token: Object.new.freeze,
111
+ controls: controls
129
112
  )
130
- unless post_control(Phronomy::Runtime.instance, command)
113
+ unless post_control(@agent.__execution_environment, command)
131
114
  fail_task(result_task, runtime_rejected_error(:start))
132
115
  end
133
116
  result_task
134
117
  rescue => error
135
- fail_task(result_task, translated(error)) if defined?(result_task) && result_task
118
+ fail_task(result_task, error) if defined?(result_task) && result_task
136
119
  result_task
137
120
  end
138
121
 
@@ -144,9 +127,8 @@ module Phronomy
144
127
  )
145
128
  @agent.send(:__assert_live_agent!)
146
129
  @agent.send(:_reject_removed_generic_identity_keys!, config)
147
- result_task = Phronomy::TaskResult.deferred(
148
- name: "agent-approval-resume:#{execution_id}"
149
- )
130
+ result_task = OperationResult.new(agent: @agent,
131
+ name: "agent-approval-resume:#{execution_id}")
150
132
  command = ResumeCommand.new(
151
133
  coordinator: self,
152
134
  execution_id: execution_id.to_s.freeze,
@@ -155,12 +137,12 @@ module Phronomy
155
137
  config: config.dup.freeze,
156
138
  result_task: result_task
157
139
  )
158
- unless post_control(Phronomy::Runtime.instance, command)
140
+ unless post_control(@agent.__execution_environment, command)
159
141
  fail_task(result_task, runtime_rejected_error(:resume))
160
142
  end
161
143
  result_task
162
144
  rescue => error
163
- fail_task(result_task, translated(error)) if defined?(result_task) && result_task
145
+ fail_task(result_task, error) if defined?(result_task) && result_task
164
146
  result_task
165
147
  end
166
148
 
@@ -178,7 +160,7 @@ module Phronomy
178
160
  submit_provider_dispatch_preparation(operation)
179
161
  nil
180
162
  rescue => error
181
- event_sink.post(:llm_setup_failed, translated(error))
163
+ event_sink.post(:llm_setup_failed, error)
182
164
  nil
183
165
  end
184
166
 
@@ -193,13 +175,13 @@ module Phronomy
193
175
  submit_tool_dispatch_preparation(operation)
194
176
  nil
195
177
  rescue => error
196
- event_sink.post(:tool_setup_failed, translated(error))
178
+ event_sink.post(:tool_setup_failed, error)
197
179
  nil
198
180
  end
199
181
 
200
182
  def submit_provider_dispatch_preparation(operation)
201
- runtime = Phronomy::Runtime.instance
202
- task = runtime.offload.submit(on_full: :raise) do
183
+ environment = @agent.__execution_environment
184
+ task = environment.submit(on_full: :raise) do
203
185
  @dispatch_preparation.prepare_provider(operation)
204
186
  end
205
187
  task.on_complete do |result, error|
@@ -209,8 +191,8 @@ module Phronomy
209
191
  result: result,
210
192
  error: error
211
193
  )
212
- unless post_control(runtime, ready)
213
- Phronomy.configuration.logger&.warn(
194
+ unless post_control(environment, ready)
195
+ Phronomy::RuntimeSettings.current.logger&.warn(
214
196
  "[Phronomy] EventLoop rejected Provider dispatch preparation result for " \
215
197
  "#{operation.execution_id}"
216
198
  )
@@ -219,8 +201,8 @@ module Phronomy
219
201
  end
220
202
 
221
203
  def submit_tool_dispatch_preparation(operation)
222
- runtime = Phronomy::Runtime.instance
223
- task = runtime.offload.submit(on_full: :raise) do
204
+ environment = @agent.__execution_environment
205
+ task = environment.submit(on_full: :raise) do
224
206
  @dispatch_preparation.prepare_tools(operation)
225
207
  end
226
208
  task.on_complete do |result, error|
@@ -230,8 +212,8 @@ module Phronomy
230
212
  result: result,
231
213
  error: error
232
214
  )
233
- unless post_control(runtime, ready)
234
- Phronomy.configuration.logger&.warn(
215
+ unless post_control(environment, ready)
216
+ Phronomy::RuntimeSettings.current.logger&.warn(
235
217
  "[Phronomy] EventLoop rejected Tool dispatch preparation result for " \
236
218
  "#{operation.execution_id}"
237
219
  )
@@ -239,70 +221,12 @@ module Phronomy
239
221
  end
240
222
  end
241
223
 
242
- def submit_provider_dispatch_preparation_reconciliation(operation, uncertainty)
243
- # simplecov:disable
244
- runtime = Phronomy::Runtime.instance
245
- command = ProviderDispatchPreparationReconciliationCommand.new(
246
- operation: operation,
247
- intended_result: uncertainty.intended_result,
248
- original_error: uncertainty.original_error
249
- )
250
- task = runtime.offload.submit(on_full: :raise) do
251
- @dispatch_preparation.reconcile_provider(command)
252
- end
253
- task.on_complete do |result, error|
254
- ready = ProviderDispatchPreparationReconciliationReady.new(
255
- coordinator: self,
256
- command: command,
257
- result: result,
258
- error: error
259
- )
260
- unless post_control(runtime, ready)
261
- Phronomy.configuration.logger&.warn(
262
- "[Phronomy] EventLoop rejected Provider dispatch reconciliation result for #{operation.execution_id}"
263
- )
264
- end
265
- end
266
- rescue => error
267
- mark_barrier_recovery_required(operation, error)
268
- # simplecov:enable
269
- end
270
-
271
- def submit_tool_dispatch_preparation_reconciliation(operation, uncertainty)
272
- # simplecov:disable
273
- runtime = Phronomy::Runtime.instance
274
- command = ToolDispatchPreparationReconciliationCommand.new(
275
- operation: operation,
276
- intended_result: uncertainty.intended_result,
277
- original_error: uncertainty.original_error
278
- )
279
- task = runtime.offload.submit(on_full: :raise) do
280
- @dispatch_preparation.reconcile_tools(command)
281
- end
282
- task.on_complete do |result, error|
283
- ready = ToolDispatchPreparationReconciliationReady.new(
284
- coordinator: self,
285
- command: command,
286
- result: result,
287
- error: error
288
- )
289
- unless post_control(runtime, ready)
290
- Phronomy.configuration.logger&.warn(
291
- "[Phronomy] EventLoop rejected Tool dispatch reconciliation result for #{operation.execution_id}"
292
- )
293
- end
294
- end
295
- rescue => error
296
- mark_barrier_recovery_required(operation, error)
297
- # simplecov:enable
298
- end
299
-
300
224
  # Every control message is delivered by EventLoop. This method is the only
301
225
  # coordinator entry point allowed to advance Phronomy-managed live state.
302
226
  # @api private
303
227
  def deliver_on_event_loop(command)
304
- event_loop = Phronomy::Runtime.instance.event_loop
305
- assert_event_loop!(event_loop)
228
+ environment = @agent.__execution_environment
229
+ assert_event_loop!(environment)
306
230
 
307
231
  case command
308
232
  when StartCommand
@@ -322,10 +246,6 @@ module Phronomy
322
246
  apply_provider_dispatch_preparation_on_event_loop(command)
323
247
  when ToolDispatchPreparationReady
324
248
  apply_tool_dispatch_preparation_on_event_loop(command)
325
- when ProviderDispatchPreparationReconciliationReady
326
- apply_provider_dispatch_preparation_reconciliation_on_event_loop(command)
327
- when ToolDispatchPreparationReconciliationReady
328
- apply_tool_dispatch_preparation_reconciliation_on_event_loop(command)
329
249
  when ResumeCommand
330
250
  begin_resume_on_event_loop(command)
331
251
  when ResumeCommitReady
@@ -346,14 +266,9 @@ module Phronomy
346
266
  # ----------------------------------------------------------------------
347
267
 
348
268
  def begin_start_on_event_loop(request)
349
- runtime = Phronomy::Runtime.instance
350
- event_loop = runtime.event_loop
351
- scope = request.config[:invocation_context]&.__execution_scope
352
- if scope && (!scope.__open? || request.config[:cancellation_token]&.cancelled?)
353
- deliver_start_failure_on_event_loop(request, scope.__cancellation_error)
354
- return
355
- end
356
- root = @agent.agent_root
269
+ environment = @agent.__execution_environment
270
+ request.controls.check_start!
271
+ root = @agent.send(:__root_for_operation)
357
272
  if root.lifecycle_status == :closed
358
273
  deliver_start_failure_on_event_loop(
359
274
  request,
@@ -365,7 +280,7 @@ module Phronomy
365
280
  @agent.send(:__assert_live_agent!)
366
281
  admitted = false
367
282
  submitted = false
368
- Phronomy::Agent::ExecutionRegistry.for(event_loop).admit_agent_execution(
283
+ environment.registry.admit_agent_execution(
369
284
  @agent.agent_id,
370
285
  owner_token: request.admission_token
371
286
  )
@@ -378,10 +293,11 @@ module Phronomy
378
293
  @agent.send(:__assert_live_agent!)
379
294
 
380
295
  operation = capture_initial_preparation(request, root)
381
- task = runtime.offload.submit(on_full: :raise) do
296
+ task = environment.submit(on_full: :raise) do
382
297
  @initial_preparation.prepare(operation)
383
298
  end
384
299
  submitted = true
300
+ request.result_task.track(task) if request.result_task.respond_to?(:track)
385
301
  task.on_complete do |result, error|
386
302
  ready = InitialPreparationReady.new(
387
303
  coordinator: self,
@@ -390,23 +306,23 @@ module Phronomy
390
306
  error: error
391
307
  )
392
308
  fail_task(request.result_task, runtime_rejected_error(:initial_preparation)) unless
393
- post_control(runtime, ready)
309
+ post_control(environment, ready)
394
310
  end
395
311
  rescue => error
396
312
  if admitted
397
313
  if submitted
398
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_admission_recovery_required(
314
+ environment.registry.mark_agent_admission_recovery_required(
399
315
  @agent.agent_id,
400
316
  owner_token: request.admission_token
401
317
  )
402
318
  else
403
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
319
+ environment.registry.release_agent_execution_admission(
404
320
  @agent.agent_id,
405
321
  owner_token: request.admission_token
406
322
  )
407
323
  end
408
324
  end
409
- deliver_start_failure_on_event_loop(request, translated(error))
325
+ deliver_start_failure_on_event_loop(request, error)
410
326
  end
411
327
 
412
328
  def capture_initial_preparation(request, root)
@@ -426,9 +342,9 @@ module Phronomy
426
342
  def initial_preparation_replayable?(input, config, approval_policy)
427
343
  return false unless input.is_a?(String)
428
344
  return false unless approval_policy.nil?
429
- if config.key?(:phronomy_handoff_bindings) ||
430
- config.key?(:phronomy_handoff_context)
431
- return false unless config[:phronomy_coordination]&.fetch("kind", nil) == "handoff"
345
+ if config.key?(:phronomy_control_bindings) ||
346
+ config.key?(:phronomy_transfer_context)
347
+ return false unless config[:phronomy_execution_participant]
432
348
  end
433
349
 
434
350
  invocation_context = config[:invocation_context]
@@ -442,40 +358,40 @@ module Phronomy
442
358
 
443
359
  def apply_initial_preparation_on_event_loop(ready)
444
360
  request = ready.request
445
- event_loop = Phronomy::Runtime.instance.event_loop
361
+ environment = @agent.__execution_environment
446
362
  if ready.error
447
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_admission_recovery_required(
363
+ environment.registry.mark_agent_admission_recovery_required(
448
364
  @agent.agent_id,
449
365
  owner_token: request.admission_token
450
366
  )
451
- deliver_start_failure_on_event_loop(request, translated(ready.error))
367
+ deliver_start_failure_on_event_loop(request, ready.error)
452
368
  return
453
369
  end
454
370
 
455
371
  result = ready.result
456
372
  case result.admission_outcome
457
373
  when :not_established
458
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
374
+ environment.registry.release_agent_execution_admission(
459
375
  @agent.agent_id,
460
376
  owner_token: request.admission_token
461
377
  )
462
378
  deliver_start_failure_on_event_loop(request, result.error)
463
379
  return
464
380
  when :outcome_unknown, :recovery_required
465
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_admission_recovery_required(
381
+ environment.registry.mark_agent_admission_recovery_required(
466
382
  @agent.agent_id,
467
383
  owner_token: request.admission_token
468
384
  )
469
385
  deliver_start_failure_on_event_loop(request, result.error)
470
386
  return
471
387
  when :active, :terminal
472
- Phronomy::Agent::ExecutionRegistry.for(event_loop).bind_agent_execution_admission(
388
+ environment.registry.bind_agent_execution_admission(
473
389
  @agent.agent_id,
474
390
  owner_token: request.admission_token,
475
391
  execution_id: result.execution.execution_id
476
392
  )
477
393
  else
478
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_admission_recovery_required(
394
+ environment.registry.mark_agent_admission_recovery_required(
479
395
  @agent.agent_id,
480
396
  owner_token: request.admission_token
481
397
  )
@@ -488,7 +404,7 @@ module Phronomy
488
404
  appended_records: result.appended_records
489
405
  )
490
406
  if result.admission_outcome == :terminal
491
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
407
+ environment.registry.release_agent_execution_admission(
492
408
  @agent.agent_id,
493
409
  execution_id: result.execution.execution_id
494
410
  )
@@ -508,8 +424,7 @@ module Phronomy
508
424
  end
509
425
 
510
426
  def register_initial_session_on_event_loop(request, prepared)
511
- runtime = Phronomy::Runtime.instance
512
- event_loop = runtime.event_loop
427
+ environment = @agent.__execution_environment
513
428
  Phronomy::Tracing::Automatic.observe_task(
514
429
  request.result_task,
515
430
  "agent.execution",
@@ -525,17 +440,17 @@ module Phronomy
525
440
  phronomy_filtered_input: prepared.filtered_input,
526
441
  execution_id: prepared.execution.execution_id
527
442
  )
528
- session = Agent::AgentInvocationSessionBuilder.build(
443
+ invocation = Agent::AgentInvocation.new(
529
444
  agent: @agent,
530
445
  input: prepared.filtered_input,
531
446
  config: effective_config,
532
447
  approval_policy: request.approval_policy,
533
448
  approval_listener: request.approval_listener,
534
449
  mode: request.mode,
535
- on_event: request.on_event,
536
- runtime: runtime
450
+ event_listener: request.on_event
537
451
  )
538
- Phronomy::Agent::ExecutionRegistry.for(event_loop).install_agent_execution(
452
+ session = environment.build_agent_session(invocation: invocation)
453
+ environment.registry.install_agent_execution(
539
454
  execution_id: prepared.execution.execution_id,
540
455
  agent: @agent,
541
456
  coordinator: self,
@@ -545,17 +460,17 @@ module Phronomy
545
460
  invocation: session.context,
546
461
  fsm_session_id: session.id
547
462
  )
548
- Phronomy::Agent::ExecutionRegistry.for(event_loop).register_agent_completion_waiter(
463
+ environment.registry.register_agent_completion_waiter(
549
464
  prepared.execution.execution_id,
550
465
  request.result_task
551
466
  )
552
- execution_session_runner(runtime).register(
467
+ execution_session_runner(environment).register(
553
468
  session, request.result_task
554
469
  )
555
470
  # simplecov:disable
556
471
  rescue => _error
557
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution(prepared.execution.execution_id) if
558
- event_loop&.current? && Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(prepared.execution.execution_id)
472
+ environment.registry.release_agent_execution(prepared.execution.execution_id) if
473
+ environment&.executing? && environment.registry.agent_execution_state(prepared.execution.execution_id)
559
474
  raise
560
475
  end
561
476
  # simplecov:enable
@@ -587,10 +502,9 @@ module Phronomy
587
502
  result_task,
588
503
  load_completion:
589
504
  )
590
- runtime = Phronomy::Runtime.instance
591
- event_loop = runtime.event_loop
592
- assert_event_loop!(event_loop)
593
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(execution.execution_id)
505
+ environment = @agent.__execution_environment
506
+ assert_event_loop!(environment)
507
+ state = environment.registry.agent_execution_state(execution.execution_id)
594
508
  unless state && state.agent.equal?(@agent) &&
595
509
  state.execution.execution_revision == execution.execution_revision &&
596
510
  state.execution.status == :preparing &&
@@ -605,10 +519,10 @@ module Phronomy
605
519
 
606
520
  operation = InitialPreparation::RecoveryCommand.new(
607
521
  execution: execution,
608
- root: @agent.agent_root,
522
+ root: @agent.send(:__root_for_operation),
609
523
  journal_records: @agent.send(:_journal_records_snapshot)
610
524
  )
611
- task = runtime.offload.submit(on_full: :raise) do
525
+ task = environment.submit(on_full: :raise) do
612
526
  @initial_preparation.recover(operation)
613
527
  end
614
528
  task.on_complete do |result, error|
@@ -621,7 +535,7 @@ module Phronomy
621
535
  result: result,
622
536
  error: error
623
537
  )
624
- unless post_control(runtime, ready)
538
+ unless post_control(environment, ready)
625
539
  rejected = runtime_rejected_error(:initial_preparation_recovery)
626
540
  fail_task(result_task, rejected)
627
541
  load_completion.fail(rejected)
@@ -630,24 +544,24 @@ module Phronomy
630
544
  rescue => error
631
545
  # simplecov:disable
632
546
  begin
633
- if defined?(event_loop) && event_loop.current?
547
+ if defined?(environment) && environment.executing?
634
548
  release_initial_preparation_recovery_runtime_state(
635
- event_loop,
549
+ environment,
636
550
  execution.execution_id
637
551
  )
638
552
  end
639
553
  rescue
640
554
  nil
641
555
  end
642
- translated_error = translated(error)
556
+ translated_error = error
643
557
  fail_task(result_task, translated_error)
644
558
  load_completion.fail(translated_error)
645
559
  # simplecov:enable
646
560
  end
647
561
 
648
562
  def apply_initial_preparation_recovery_on_event_loop(ready)
649
- event_loop = Phronomy::Runtime.instance.event_loop
650
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(ready.execution_id)
563
+ environment = @agent.__execution_environment
564
+ state = environment.registry.agent_execution_state(ready.execution_id)
651
565
  unless state && state.agent.equal?(@agent) &&
652
566
  state.execution.execution_revision == ready.expected_execution_revision &&
653
567
  state.execution.status == :preparing &&
@@ -662,10 +576,10 @@ module Phronomy
662
576
 
663
577
  if ready.error
664
578
  release_initial_preparation_recovery_runtime_state(
665
- event_loop,
579
+ environment,
666
580
  ready.execution_id
667
581
  )
668
- error = translated(ready.error)
582
+ error = ready.error
669
583
  fail_task(ready.result_task, error)
670
584
  ready.load_completion.fail(error)
671
585
  return
@@ -674,17 +588,17 @@ module Phronomy
674
588
  result = ready.result
675
589
  case result.admission_outcome
676
590
  when :terminal
677
- settle_failed_preparation_recovery_on_event_loop(ready, event_loop)
591
+ settle_failed_preparation_recovery_on_event_loop(ready, environment)
678
592
  ready.load_completion.complete(@agent)
679
593
  when :active
680
- restart_prepared_execution_on_event_loop(ready, event_loop)
594
+ restart_prepared_execution_on_event_loop(ready, environment)
681
595
  ready.load_completion.complete(@agent)
682
596
  else
683
597
  error = Phronomy::ExecutionRehydrationRequiredError.new(
684
598
  "unexpected initial preparation Recovery outcome: #{result.admission_outcome.inspect}"
685
599
  )
686
600
  release_initial_preparation_recovery_runtime_state(
687
- event_loop,
601
+ environment,
688
602
  ready.execution_id
689
603
  )
690
604
  fail_task(ready.result_task, error)
@@ -694,30 +608,30 @@ module Phronomy
694
608
  # simplecov:disable
695
609
  begin
696
610
  release_initial_preparation_recovery_runtime_state(
697
- event_loop,
611
+ environment,
698
612
  ready.execution_id
699
613
  )
700
614
  rescue
701
615
  nil
702
616
  end
703
- translated_error = translated(error)
617
+ translated_error = error
704
618
  fail_task(ready.result_task, translated_error)
705
619
  ready.load_completion.fail(translated_error)
706
620
  # simplecov:enable
707
621
  end
708
622
 
709
- def settle_failed_preparation_recovery_on_event_loop(ready, event_loop)
623
+ def settle_failed_preparation_recovery_on_event_loop(ready, environment)
710
624
  result = ready.result
711
625
  apply_agent_live_state(
712
626
  root: result.root,
713
627
  appended_records: result.appended_records
714
628
  )
715
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
629
+ environment.registry.replace_agent_execution(
716
630
  ready.execution_id,
717
631
  execution: result.execution
718
632
  )
719
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution(ready.execution_id)
720
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
633
+ environment.registry.release_agent_execution(ready.execution_id)
634
+ environment.registry.release_agent_execution_admission(
721
635
  @agent.agent_id,
722
636
  execution_id: ready.execution_id
723
637
  )
@@ -736,13 +650,13 @@ module Phronomy
736
650
  )
737
651
  end
738
652
 
739
- def restart_prepared_execution_on_event_loop(ready, event_loop)
653
+ def restart_prepared_execution_on_event_loop(ready, environment)
740
654
  result = ready.result
741
655
  apply_agent_live_state(
742
656
  root: result.root,
743
657
  appended_records: result.appended_records
744
658
  )
745
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution(ready.execution_id)
659
+ environment.registry.release_agent_execution(ready.execution_id)
746
660
  mode = (
747
661
  result.execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] ||
748
662
  "invoke"
@@ -756,7 +670,8 @@ module Phronomy
756
670
  approval_listener: nil,
757
671
  on_event: @agent.send(:_phronomy_event_listener),
758
672
  result_task: ready.result_task,
759
- admission_token: Object.new.freeze
673
+ admission_token: Object.new.freeze,
674
+ controls: nil
760
675
  )
761
676
  begin
762
677
  register_initial_session_on_event_loop(request, result)
@@ -770,12 +685,12 @@ module Phronomy
770
685
  end
771
686
 
772
687
  def release_initial_preparation_recovery_runtime_state(
773
- event_loop,
688
+ environment,
774
689
  execution_id
775
690
  )
776
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(execution_id)
777
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution(execution_id) if state
778
- Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
691
+ state = environment.registry.agent_execution_state(execution_id)
692
+ environment.registry.release_agent_execution(execution_id) if state
693
+ environment.registry.release_agent_execution_admission(
779
694
  @agent.agent_id,
780
695
  execution_id: execution_id
781
696
  )
@@ -786,11 +701,11 @@ module Phronomy
786
701
  # ----------------------------------------------------------------------
787
702
 
788
703
  def dispatch_preparation_state!(invocation, event_sink, phase:, kind:)
789
- event_loop = Phronomy::Runtime.instance.event_loop
790
- assert_event_loop!(event_loop)
791
- state = ExecutionRegistry.for(event_loop).agent_execution_state(invocation.execution_id)
704
+ environment = @agent.__execution_environment
705
+ assert_event_loop!(environment)
706
+ state = environment.registry.agent_execution_state(invocation.execution_id)
792
707
  validate_live_session!(state, invocation, event_sink.fsm_session_id)
793
- unless event_loop.fsm_session_state(event_sink.fsm_session_id) == phase
708
+ unless environment.session_phase(event_sink.fsm_session_id) == phase
794
709
  raise Phronomy::Error,
795
710
  "#{kind} dispatch preparation requires the owning FSMSession to be in #{phase.inspect}"
796
711
  end
@@ -802,7 +717,7 @@ module Phronomy
802
717
  execution_id: state.execution_id,
803
718
  fsm_session_id: fsm_session_id.to_s.freeze,
804
719
  expected_execution_revision: state.execution.execution_revision,
805
- root: @agent.agent_root,
720
+ root: @agent.send(:__root_for_operation),
806
721
  journal_records: @agent.send(:_journal_records_snapshot),
807
722
  execution: state.execution,
808
723
  base_manifest: state.base_manifest,
@@ -824,10 +739,11 @@ module Phronomy
824
739
  execution_id: state.execution_id,
825
740
  fsm_session_id: fsm_session_id.to_s.freeze,
826
741
  expected_execution_revision: state.execution.execution_revision,
827
- root: @agent.agent_root,
742
+ root: @agent.send(:__root_for_operation),
828
743
  execution: state.execution,
829
744
  runtime_snapshot: invocation.runtime_snapshot,
830
- tool_batch_snapshot: tool_batch_snapshot
745
+ tool_batch_snapshot: tool_batch_snapshot,
746
+ invocation_config: invocation.config.dup.freeze
831
747
  )
832
748
  end
833
749
 
@@ -842,13 +758,10 @@ module Phronomy
842
758
  return unless state
843
759
 
844
760
  if ready.error
845
- if ready.error.is_a?(PreparationOutcomeUnknownError)
846
- submit_provider_dispatch_preparation_reconciliation(
847
- operation,
848
- ready.error
849
- )
761
+ if ready.error.is_a?(Phronomy::ExecutionRehydrationRequiredError)
762
+ mark_barrier_recovery_required(operation, ready.error)
850
763
  else
851
- state.invocation.event_sink.post(:llm_setup_failed, translated(ready.error))
764
+ state.invocation.event_sink.post(:llm_setup_failed, ready.error)
852
765
  end
853
766
  return
854
767
  end
@@ -859,7 +772,7 @@ module Phronomy
859
772
  state
860
773
  )
861
774
  rescue => error
862
- state&.invocation&.event_sink&.post(:llm_setup_failed, translated(error))
775
+ state&.invocation&.event_sink&.post(:llm_setup_failed, error)
863
776
  end
864
777
 
865
778
  def apply_tool_dispatch_preparation_on_event_loop(ready)
@@ -873,13 +786,10 @@ module Phronomy
873
786
  return unless state
874
787
 
875
788
  if ready.error
876
- if ready.error.is_a?(PreparationOutcomeUnknownError)
877
- submit_tool_dispatch_preparation_reconciliation(
878
- operation,
879
- ready.error
880
- )
789
+ if ready.error.is_a?(Phronomy::ExecutionRehydrationRequiredError)
790
+ mark_barrier_recovery_required(operation, ready.error)
881
791
  else
882
- state.invocation.event_sink.post(:tool_setup_failed, translated(ready.error))
792
+ state.invocation.event_sink.post(:tool_setup_failed, ready.error)
883
793
  end
884
794
  return
885
795
  end
@@ -890,7 +800,7 @@ module Phronomy
890
800
  state
891
801
  )
892
802
  rescue => error
893
- state&.invocation&.event_sink&.post(:tool_setup_failed, translated(error))
803
+ state&.invocation&.event_sink&.post(:tool_setup_failed, error)
894
804
  end
895
805
 
896
806
  def apply_confirmed_provider_dispatch_preparation_on_event_loop(
@@ -898,15 +808,15 @@ module Phronomy
898
808
  result,
899
809
  state
900
810
  )
901
- event_loop = Phronomy::Runtime.instance.event_loop
811
+ environment = @agent.__execution_environment
902
812
  if result.runtime_projection
903
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
813
+ environment.registry.replace_agent_execution(
904
814
  operation.execution_id,
905
815
  execution: result.execution,
906
816
  runtime_projection: result.runtime_projection
907
817
  )
908
818
  else
909
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
819
+ environment.registry.replace_agent_execution(
910
820
  operation.execution_id,
911
821
  execution: result.execution
912
822
  )
@@ -914,13 +824,13 @@ module Phronomy
914
824
  state.invocation.acknowledge_runtime_snapshot(operation.runtime_snapshot)
915
825
 
916
826
  if result.error
917
- state.invocation.event_sink.post(:llm_setup_failed, translated(result.error))
827
+ state.invocation.event_sink.post(:llm_setup_failed, result.error)
918
828
  return
919
829
  end
920
830
 
921
- Agent::AgentInvocationSessionBuilder.start_prepared_provider_call(
831
+ Agent::InvocationActions.start_prepared_provider_call(
922
832
  agent: @agent,
923
- runtime: Phronomy::Runtime.instance,
833
+ environment: @agent.__execution_environment,
924
834
  event_sink: state.invocation.event_sink,
925
835
  invocation: state.invocation,
926
836
  projection: result.runtime_projection,
@@ -933,106 +843,27 @@ module Phronomy
933
843
  result,
934
844
  state
935
845
  )
936
- event_loop = Phronomy::Runtime.instance.event_loop
937
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
846
+ environment = @agent.__execution_environment
847
+ environment.registry.replace_agent_execution(
938
848
  operation.execution_id,
939
849
  execution: result.execution
940
850
  )
941
851
  state.invocation.acknowledge_runtime_snapshot(operation.runtime_snapshot)
942
- Agent::AgentInvocationSessionBuilder.start_prepared_tool_dispatch(
943
- runtime: Phronomy::Runtime.instance,
852
+ Agent::InvocationActions.start_prepared_tool_dispatch(
853
+ environment: @agent.__execution_environment,
944
854
  event_sink: state.invocation.event_sink,
945
855
  invocation: state.invocation
946
856
  )
947
857
  end
948
858
 
949
- def apply_provider_dispatch_preparation_reconciliation_on_event_loop(ready)
950
- command = ready.command
951
- operation = command.operation
952
- state = authoritative_state_for_operation(
953
- execution_id: operation.execution_id,
954
- fsm_session_id: operation.fsm_session_id,
955
- expected_execution_revision: operation.expected_execution_revision,
956
- expected_fsm_state: :calling_llm
957
- )
958
- return unless state
959
-
960
- if ready.error
961
- mark_barrier_recovery_required(operation, ready.error)
962
- return
963
- end
964
-
965
- case ready.result.disposition
966
- when :committed
967
- apply_confirmed_provider_dispatch_preparation_on_event_loop(
968
- operation,
969
- ready.result.preparation_result,
970
- state
971
- )
972
- when :not_committed
973
- state.invocation.event_sink.post(
974
- :llm_setup_failed,
975
- translated(command.original_error)
976
- )
977
- when :conflict
978
- mark_barrier_recovery_required(operation, command.original_error)
979
- else
980
- raise Phronomy::Error,
981
- "unknown Provider dispatch reconciliation disposition: " \
982
- "#{ready.result.disposition.inspect}"
983
- end
984
- rescue => error
985
- mark_barrier_recovery_required(operation, error)
986
- end
987
-
988
- def apply_tool_dispatch_preparation_reconciliation_on_event_loop(ready)
989
- command = ready.command
990
- operation = command.operation
991
- state = authoritative_state_for_operation(
992
- execution_id: operation.execution_id,
993
- fsm_session_id: operation.fsm_session_id,
994
- expected_execution_revision: operation.expected_execution_revision,
995
- expected_fsm_state: :dispatching_tools
996
- )
997
- return unless state
998
-
999
- if ready.error
1000
- mark_barrier_recovery_required(operation, ready.error)
1001
- return
1002
- end
1003
-
1004
- case ready.result.disposition
1005
- when :committed
1006
- apply_confirmed_tool_dispatch_preparation_on_event_loop(
1007
- operation,
1008
- ready.result.preparation_result,
1009
- state
1010
- )
1011
- when :not_committed
1012
- state.invocation.event_sink.post(
1013
- :tool_setup_failed,
1014
- translated(command.original_error)
1015
- )
1016
- when :conflict
1017
- mark_barrier_recovery_required(operation, command.original_error)
1018
- else
1019
- raise Phronomy::Error,
1020
- "unknown Tool dispatch reconciliation disposition: " \
1021
- "#{ready.result.disposition.inspect}"
1022
- end
1023
- rescue => error
1024
- mark_barrier_recovery_required(operation, error)
1025
- # simplecov:enable
1026
- end
1027
-
1028
859
  def mark_barrier_recovery_required(operation, error)
1029
- event_loop = Phronomy::Runtime.instance.event_loop
1030
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
860
+ environment = @agent.__execution_environment
861
+ environment.registry.mark_agent_execution_admission(
1031
862
  @agent.agent_id,
1032
863
  execution_id: operation.execution_id,
1033
864
  state: :recovery_required
1034
865
  )
1035
- Phronomy.configuration.logger&.warn(
866
+ Phronomy::RuntimeSettings.current.logger&.warn(
1036
867
  "[Phronomy] causal durable barrier requires recovery for " \
1037
868
  "#{operation.execution_id}: #{error.class}: #{error.message}"
1038
869
  )
@@ -1043,9 +874,8 @@ module Phronomy
1043
874
  # ----------------------------------------------------------------------
1044
875
 
1045
876
  def begin_resume_on_event_loop(request)
1046
- runtime = Phronomy::Runtime.instance
1047
- event_loop = runtime.event_loop
1048
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(request.execution_id)
877
+ environment = @agent.__execution_environment
878
+ state = environment.registry.agent_execution_state(request.execution_id)
1049
879
  unless state
1050
880
  fail_task(
1051
881
  request.result_task,
@@ -1081,16 +911,17 @@ module Phronomy
1081
911
  operation = capture_approval_resume(state, request)
1082
912
  resume_transition_started = false
1083
913
  submitted = false
1084
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
914
+ environment.registry.mark_agent_execution_admission(
1085
915
  @agent.agent_id,
1086
916
  execution_id: state.execution_id,
1087
917
  state: :resuming
1088
918
  )
1089
919
  resume_transition_started = true
1090
- task = runtime.offload.submit(on_full: :raise) do
920
+ task = environment.submit(on_full: :raise) do
1091
921
  @approval_resume_commit.commit(operation)
1092
922
  end
1093
923
  submitted = true
924
+ request.result_task.track(task) if request.result_task.respond_to?(:track)
1094
925
  task.on_complete do |result, error|
1095
926
  ready = ResumeCommitReady.new(
1096
927
  coordinator: self,
@@ -1100,17 +931,17 @@ module Phronomy
1100
931
  error: error
1101
932
  )
1102
933
  fail_task(request.result_task, runtime_rejected_error(:resume_commit)) unless
1103
- post_control(runtime, ready)
934
+ post_control(environment, ready)
1104
935
  end
1105
936
  rescue => error
1106
937
  if resume_transition_started
1107
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
938
+ environment.registry.mark_agent_execution_admission(
1108
939
  @agent.agent_id,
1109
940
  execution_id: state.execution_id,
1110
941
  state: submitted ? :recovery_required : :suspended
1111
942
  )
1112
943
  end
1113
- fail_task(request.result_task, translated(error))
944
+ fail_task(request.result_task, error)
1114
945
  raise unless resume_transition_started
1115
946
  end
1116
947
 
@@ -1123,7 +954,7 @@ module Phronomy
1123
954
  ResumeCommitCommand.new(
1124
955
  execution_id: state.execution_id,
1125
956
  expected_execution_revision: state.execution.execution_revision,
1126
- root: @agent.agent_root,
957
+ root: @agent.send(:__root_for_operation),
1127
958
  execution: state.execution,
1128
959
  approval_request_id: request.approval_request_id,
1129
960
  approved: request.approved,
@@ -1134,8 +965,8 @@ module Phronomy
1134
965
  def apply_resume_commit_on_event_loop(ready)
1135
966
  request = ready.request
1136
967
  operation = ready.operation
1137
- event_loop = Phronomy::Runtime.instance.event_loop
1138
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(operation.execution_id)
968
+ environment = @agent.__execution_environment
969
+ state = environment.registry.agent_execution_state(operation.execution_id)
1139
970
  unless state && state.agent.equal?(@agent) &&
1140
971
  state.execution.execution_revision == operation.expected_execution_revision &&
1141
972
  state.execution.status == :suspended
@@ -1149,23 +980,23 @@ module Phronomy
1149
980
  end
1150
981
 
1151
982
  if ready.error
1152
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
983
+ environment.registry.mark_agent_execution_admission(
1153
984
  @agent.agent_id,
1154
985
  execution_id: operation.execution_id,
1155
986
  state: :recovery_required
1156
987
  )
1157
- fail_task(request.result_task, translated(ready.error))
988
+ fail_task(request.result_task, ready.error)
1158
989
  return
1159
990
  end
1160
991
 
1161
- install_resumed_execution_on_event_loop(ready, event_loop)
992
+ install_resumed_execution_on_event_loop(ready, environment)
1162
993
  observe_resumed_execution(ready, state)
1163
- execution_session_runner(Phronomy::Runtime.instance).resume_approval(
994
+ execution_session_runner(@agent.__execution_environment).resume_approval(
1164
995
  state.invocation, request.result_task,
1165
996
  approved: request.approved, config: request.config
1166
997
  )
1167
998
  rescue => error
1168
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(operation.execution_id) if event_loop&.current?
999
+ state = environment.registry.agent_execution_state(operation.execution_id) if environment&.executing?
1169
1000
  if state
1170
1001
  begin_terminal_commit_on_event_loop(
1171
1002
  state,
@@ -1175,24 +1006,24 @@ module Phronomy
1175
1006
  fsm_session_id: state.fsm_session_id
1176
1007
  )
1177
1008
  else
1178
- fail_task(request.result_task, translated(error))
1009
+ fail_task(request.result_task, error)
1179
1010
  end
1180
1011
  end
1181
1012
 
1182
- def install_resumed_execution_on_event_loop(ready, event_loop)
1013
+ def install_resumed_execution_on_event_loop(ready, environment)
1183
1014
  request = ready.request
1184
1015
  operation = ready.operation
1185
1016
  apply_agent_live_state(root: ready.result.root, appended_records: [])
1186
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1017
+ environment.registry.mark_agent_execution_admission(
1187
1018
  @agent.agent_id,
1188
1019
  execution_id: operation.execution_id,
1189
1020
  state: :executing
1190
1021
  )
1191
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
1022
+ environment.registry.replace_agent_execution(
1192
1023
  operation.execution_id,
1193
1024
  execution: ready.result.execution
1194
1025
  )
1195
- Phronomy::Agent::ExecutionRegistry.for(event_loop).register_agent_completion_waiter(
1026
+ environment.registry.register_agent_completion_waiter(
1196
1027
  operation.execution_id,
1197
1028
  request.result_task
1198
1029
  )
@@ -1227,20 +1058,20 @@ module Phronomy
1227
1058
  raise Phronomy::ExecutionRehydrationRequiredError,
1228
1059
  "initial preparation continuation requires a :preparing execution"
1229
1060
  end
1230
- ExecutionRegistry.for(Phronomy::Runtime.instance.event_loop).mark_agent_execution_admission(
1061
+ @agent.__execution_environment.registry.mark_agent_execution_admission(
1231
1062
  @agent.agent_id, execution_id: state.execution_id, state: :executing
1232
1063
  )
1233
1064
  start_initial_preparation_recovery_on_event_loop(
1234
1065
  state.execution, command.result_task, load_completion: command.load_completion
1235
1066
  )
1236
1067
  rescue => error
1237
- fail_task(command.result_task, translated(error))
1238
- command.load_completion.fail(translated(error))
1068
+ fail_task(command.result_task, error)
1069
+ command.load_completion.fail(error)
1239
1070
  end
1240
1071
 
1241
1072
  def continue_recovered_on_event_loop(command)
1242
- runtime = Phronomy::Runtime.instance
1243
- registry = ExecutionRegistry.for(runtime.event_loop)
1073
+ environment = @agent.__execution_environment
1074
+ registry = environment.registry
1244
1075
  state = recovered_execution_state!(command)
1245
1076
  validate_recovered_continuation!(state.execution, command.continuation)
1246
1077
  invocation = command.invocation
@@ -1265,7 +1096,7 @@ module Phronomy
1265
1096
  registry.mark_agent_execution_admission(@agent.agent_id,
1266
1097
  execution_id: state.execution_id, state: :executing)
1267
1098
  registry.register_agent_completion_waiter(state.execution_id, command.result_task)
1268
- runner = execution_session_runner(runtime)
1099
+ runner = execution_session_runner(environment)
1269
1100
  case command.continuation
1270
1101
  when :approval_rejection
1271
1102
  runner.resume_approval(invocation, command.result_task, approved: false, config: {})
@@ -1281,7 +1112,7 @@ module Phronomy
1281
1112
  end
1282
1113
 
1283
1114
  def recovered_execution_state!(command)
1284
- state = ExecutionRegistry.for(Phronomy::Runtime.instance.event_loop).agent_execution_state(command.execution_id)
1115
+ state = @agent.__execution_environment.registry.agent_execution_state(command.execution_id)
1285
1116
  unless command.coordinator.equal?(self) && state && state.agent.equal?(@agent) &&
1286
1117
  state.coordinator.equal?(self) && state.execution.active? &&
1287
1118
  state.execution.execution_revision == command.expected_execution_revision &&
@@ -1292,8 +1123,8 @@ module Phronomy
1292
1123
  state
1293
1124
  end
1294
1125
 
1295
- def execution_session_runner(runtime)
1296
- ExecutionSessionRunner.new(runtime: runtime, on_complete: ->(**result) {
1126
+ def execution_session_runner(environment)
1127
+ ExecutionSessionRunner.new(environment: environment, on_complete: ->(**result) {
1297
1128
  deliver_on_event_loop(SessionFinishedCommand.new(coordinator: self, **result))
1298
1129
  })
1299
1130
  end
@@ -1327,9 +1158,9 @@ module Phronomy
1327
1158
  # ----------------------------------------------------------------------
1328
1159
 
1329
1160
  def finish_on_event_loop(execution_id, result_task, invocation, error, fsm_session_id:)
1330
- event_loop = Phronomy::Runtime.instance.event_loop
1331
- assert_event_loop!(event_loop)
1332
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(execution_id)
1161
+ environment = @agent.__execution_environment
1162
+ assert_event_loop!(environment)
1163
+ state = environment.registry.agent_execution_state(execution_id)
1333
1164
  return fail_task(result_task, runtime_rejected_error(:terminal)) unless state
1334
1165
 
1335
1166
  unless state.agent.equal?(@agent) && state.coordinator.equal?(self) &&
@@ -1342,15 +1173,15 @@ module Phronomy
1342
1173
  end
1343
1174
 
1344
1175
  terminal_error = error || invocation&.error
1345
- unless Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_quiescent?(execution_id)
1176
+ unless environment.registry.agent_execution_quiescent?(execution_id)
1346
1177
  wait_state = quiescence_sensitive_terminal_error?(terminal_error) ?
1347
1178
  :cancelling : :terminalizing
1348
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1179
+ environment.registry.mark_agent_execution_admission(
1349
1180
  @agent.agent_id,
1350
1181
  execution_id: execution_id,
1351
1182
  state: wait_state
1352
1183
  )
1353
- Phronomy::Agent::ExecutionRegistry.for(event_loop).defer_agent_terminal_until_quiescent(
1184
+ environment.registry.defer_agent_terminal_until_quiescent(
1354
1185
  execution_id,
1355
1186
  DeferredTerminalCommand.new(
1356
1187
  coordinator: self,
@@ -1374,18 +1205,18 @@ module Phronomy
1374
1205
  end
1375
1206
 
1376
1207
  def resume_deferred_terminal_on_event_loop(command)
1377
- event_loop = Phronomy::Runtime.instance.event_loop
1378
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(command.execution_id)
1208
+ environment = @agent.__execution_environment
1209
+ state = environment.registry.agent_execution_state(command.execution_id)
1379
1210
  unless state && state.agent.equal?(@agent) &&
1380
1211
  state.fsm_session_id.to_s == command.fsm_session_id.to_s &&
1381
1212
  state.invocation.equal?(command.invocation)
1382
- Phronomy.configuration.logger&.warn(
1213
+ Phronomy::RuntimeSettings.current.logger&.warn(
1383
1214
  "[Phronomy] Dropped stale deferred terminal for #{command.execution_id}"
1384
1215
  )
1385
1216
  return
1386
1217
  end
1387
1218
 
1388
- unless Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_quiescent?(command.execution_id)
1219
+ unless environment.registry.agent_execution_quiescent?(command.execution_id)
1389
1220
  raise Phronomy::Error,
1390
1221
  "deferred terminal resumed before quiescence for #{command.execution_id}"
1391
1222
  end
@@ -1424,7 +1255,7 @@ module Phronomy
1424
1255
 
1425
1256
  operation = build_terminal_operation(
1426
1257
  execution: state.execution,
1427
- root: @agent.agent_root,
1258
+ root: @agent.send(:__root_for_operation),
1428
1259
  journal_records: @agent.send(:_journal_records_snapshot),
1429
1260
  invocation: invocation,
1430
1261
  source_error: source_error,
@@ -1442,7 +1273,7 @@ module Phronomy
1442
1273
  end
1443
1274
 
1444
1275
  def begin_terminal_without_session_on_event_loop(request:, prepared:, error:)
1445
- return deliver_start_failure_on_event_loop(request, translated(error)) unless prepared&.execution
1276
+ return deliver_start_failure_on_event_loop(request, error) unless prepared&.execution
1446
1277
 
1447
1278
  operation = build_terminal_operation(
1448
1279
  execution: prepared.execution,
@@ -1481,7 +1312,8 @@ module Phronomy
1481
1312
  execution: execution,
1482
1313
  runtime_snapshot: invocation ? invocation.runtime_snapshot : empty_runtime_snapshot,
1483
1314
  terminal_view: terminal_view(invocation, source_error),
1484
- state_required: state_required
1315
+ state_required: state_required,
1316
+ wiring: (invocation ? invocation.config : @agent.__execution_wiring).dup.freeze
1485
1317
  )
1486
1318
  end
1487
1319
 
@@ -1490,24 +1322,24 @@ module Phronomy
1490
1322
  end
1491
1323
 
1492
1324
  def submit_terminal_operation(operation, delivery)
1493
- runtime = Phronomy::Runtime.instance
1494
- event_loop = runtime.event_loop
1325
+ environment = @agent.__execution_environment
1495
1326
  terminal_transition_started = false
1496
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1327
+ environment.registry.mark_agent_execution_admission(
1497
1328
  @agent.agent_id,
1498
1329
  execution_id: operation.execution_id,
1499
1330
  state: :terminalizing
1500
1331
  )
1501
1332
  terminal_transition_started = true
1502
- Phronomy::Agent::ExecutionRegistry.for(event_loop).register_agent_completion_waiter(
1333
+ environment.registry.register_agent_completion_waiter(
1503
1334
  operation.execution_id,
1504
1335
  delivery.result_task
1505
1336
  )
1506
- task = runtime.offload.submit(on_full: :raise) do
1337
+ task = environment.submit(on_full: :raise) do
1507
1338
  # Only the operation-specific immutable durable snapshot crosses the
1508
1339
  # worker boundary. TaskResult/listener delivery state stays outside it.
1509
1340
  @outcome_committer.commit_outcome(operation)
1510
1341
  end
1342
+ delivery.result_task.track(task) if delivery.result_task.respond_to?(:track)
1511
1343
  task.on_complete do |outcome, error|
1512
1344
  ready = TerminalCommitReady.new(
1513
1345
  coordinator: self,
@@ -1517,23 +1349,23 @@ module Phronomy
1517
1349
  error: error
1518
1350
  )
1519
1351
  fail_task(delivery.result_task, runtime_rejected_error(:terminal_apply)) unless
1520
- post_control(runtime, ready)
1352
+ post_control(environment, ready)
1521
1353
  end
1522
1354
  rescue => error
1523
1355
  if terminal_transition_started
1524
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1356
+ environment.registry.mark_agent_execution_admission(
1525
1357
  @agent.agent_id,
1526
1358
  execution_id: operation.execution_id,
1527
1359
  state: :recovery_required
1528
1360
  )
1529
- Phronomy.configuration.logger&.warn(
1361
+ Phronomy::RuntimeSettings.current.logger&.warn(
1530
1362
  "[Phronomy] Agent terminal transition requires recovery for " \
1531
1363
  "#{operation.execution_id}: #{error.class}: #{error.message}"
1532
1364
  )
1533
1365
  return
1534
1366
  end
1535
1367
 
1536
- fail_task(delivery.result_task, translated(error))
1368
+ fail_task(delivery.result_task, error)
1537
1369
  raise
1538
1370
  end
1539
1371
 
@@ -1555,20 +1387,7 @@ module Phronomy
1555
1387
  )
1556
1388
  end
1557
1389
 
1558
- def handoff_terminal_view(request)
1559
- return unless request
1560
-
1561
- HandoffTerminalView.new(
1562
- target_agent_id: request.handoff.target_agent.agent_id.to_s.freeze,
1563
- responsibility: request.responsibility.to_s.freeze,
1564
- selection_intent: request.selection_intent.to_h do |category, included|
1565
- [category.to_s.freeze, !!included]
1566
- end.freeze,
1567
- llm_call_id: request.llm_call_id&.to_s&.freeze,
1568
- tool_call_id: request.tool_call_id&.to_s&.freeze,
1569
- policy: Phronomy::Values::Immutable.copy(request.handoff.policy.to_h)
1570
- )
1571
- end
1390
+ def handoff_terminal_view(request) = request
1572
1391
 
1573
1392
  def empty_runtime_snapshot
1574
1393
  {llm_results: [].freeze, runtime_events: [].freeze, active_call: nil}.freeze
@@ -1577,14 +1396,14 @@ module Phronomy
1577
1396
  def apply_terminal_commit_on_event_loop(ready)
1578
1397
  operation = ready.operation
1579
1398
  delivery = ready.delivery
1580
- event_loop = Phronomy::Runtime.instance.event_loop
1581
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(operation.execution_id)
1399
+ environment = @agent.__execution_environment
1400
+ state = environment.registry.agent_execution_state(operation.execution_id)
1582
1401
 
1583
1402
  if operation.state_required
1584
1403
  unless state && state.agent.equal?(@agent) &&
1585
1404
  state.execution.execution_revision == operation.expected_execution_revision &&
1586
1405
  state.fsm_session_id.to_s == operation.fsm_session_id.to_s
1587
- Phronomy.configuration.logger&.warn(
1406
+ Phronomy::RuntimeSettings.current.logger&.warn(
1588
1407
  "[Phronomy] Dropped stale Agent terminal result for #{operation.execution_id}"
1589
1408
  )
1590
1409
  return
@@ -1592,23 +1411,23 @@ module Phronomy
1592
1411
  end
1593
1412
 
1594
1413
  if ready.error
1595
- handle_terminal_commit_error_on_event_loop(ready, state, event_loop)
1414
+ handle_terminal_commit_error_on_event_loop(ready, state, environment)
1596
1415
  return
1597
1416
  end
1598
1417
 
1599
- apply_terminal_outcome_state_on_event_loop(ready, state, event_loop)
1418
+ apply_terminal_outcome_state_on_event_loop(ready, state, environment)
1600
1419
  outcome = ready.outcome
1601
1420
  case outcome.type
1602
1421
  when :coordination_wait
1603
- release_coordination_wait_on_event_loop(ready, state, event_loop)
1422
+ release_coordination_wait_on_event_loop(ready, state, environment)
1604
1423
  when :suspended
1605
- suspend_execution_on_event_loop(ready, state, event_loop)
1424
+ suspend_execution_on_event_loop(ready, state, environment)
1606
1425
  when :completed
1607
- deliver_completed_execution_on_event_loop(ready, state, event_loop)
1426
+ deliver_completed_execution_on_event_loop(ready, state, environment)
1608
1427
  when :handed_off
1609
- deliver_handoff_on_event_loop(ready, state, event_loop)
1428
+ deliver_handoff_on_event_loop(ready, state, environment)
1610
1429
  when :failed
1611
- deliver_failed_execution_on_event_loop(ready, state, event_loop)
1430
+ deliver_failed_execution_on_event_loop(ready, state, environment)
1612
1431
  else
1613
1432
  fail_task(
1614
1433
  delivery.result_task,
@@ -1617,28 +1436,28 @@ module Phronomy
1617
1436
  end
1618
1437
  end
1619
1438
 
1620
- def handle_terminal_commit_error_on_event_loop(ready, state, event_loop)
1439
+ def handle_terminal_commit_error_on_event_loop(ready, state, environment)
1621
1440
  operation = ready.operation
1622
1441
  delivery = ready.delivery
1623
- if operation.execution.metadata["coordination"] || operation.execution.metadata["multi_agent_coordination_ref"]
1624
- release_terminal_ownership(event_loop, operation.execution_id, state)
1625
- Phronomy::Agent::ExecutionRegistry.for(event_loop).take_agent_completion_waiters(operation.execution_id, fallback: delivery.result_task).each do |task|
1626
- task.fail(ready.error)
1442
+ if operation.execution.metadata["reservation"] || operation.execution.metadata["execution_extension"]
1443
+ release_terminal_ownership(environment, operation.execution_id, state)
1444
+ environment.registry.take_agent_completion_waiters(operation.execution_id, fallback: delivery.result_task).each do |task|
1445
+ fail_task(task, ready.error)
1627
1446
  end
1628
1447
  return
1629
1448
  end
1630
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1449
+ environment.registry.mark_agent_execution_admission(
1631
1450
  @agent.agent_id,
1632
1451
  execution_id: operation.execution_id,
1633
1452
  state: :recovery_required
1634
1453
  )
1635
- Phronomy.configuration.logger&.warn(
1454
+ Phronomy::RuntimeSettings.current.logger&.warn(
1636
1455
  "[Phronomy] Agent terminal durable outcome requires recovery for " \
1637
1456
  "#{operation.execution_id}: #{ready.error.class}: #{ready.error.message}"
1638
1457
  )
1639
1458
  end
1640
1459
 
1641
- def apply_terminal_outcome_state_on_event_loop(ready, state, event_loop)
1460
+ def apply_terminal_outcome_state_on_event_loop(ready, state, environment)
1642
1461
  operation = ready.operation
1643
1462
  outcome = ready.outcome
1644
1463
  apply_agent_live_state(
@@ -1647,7 +1466,7 @@ module Phronomy
1647
1466
  )
1648
1467
  if state
1649
1468
  state.invocation&.acknowledge_runtime_snapshot(operation.runtime_snapshot)
1650
- Phronomy::Agent::ExecutionRegistry.for(event_loop).replace_agent_execution(
1469
+ environment.registry.replace_agent_execution(
1651
1470
  operation.execution_id,
1652
1471
  execution: outcome.execution,
1653
1472
  fsm_session_id: (outcome.type == :suspended) ? nil : state.fsm_session_id
@@ -1655,19 +1474,19 @@ module Phronomy
1655
1474
  end
1656
1475
  end
1657
1476
 
1658
- def release_coordination_wait_on_event_loop(ready, state, event_loop)
1477
+ def release_coordination_wait_on_event_loop(ready, state, environment)
1659
1478
  operation = ready.operation
1660
1479
  delivery = ready.delivery
1661
1480
  outcome = ready.outcome
1662
- release_terminal_ownership(event_loop, operation.execution_id, state)
1663
- Phronomy::Agent::ExecutionRegistry.for(event_loop).take_agent_completion_waiters(operation.execution_id, fallback: delivery.result_task).each { |task| task.fail(outcome.error) }
1481
+ release_terminal_ownership(environment, operation.execution_id, state)
1482
+ environment.registry.take_agent_completion_waiters(operation.execution_id, fallback: delivery.result_task).each { |task| fail_task(task, outcome.error) }
1664
1483
  end
1665
1484
 
1666
- def suspend_execution_on_event_loop(ready, state, event_loop)
1485
+ def suspend_execution_on_event_loop(ready, state, environment)
1667
1486
  operation = ready.operation
1668
1487
  delivery = ready.delivery
1669
1488
  outcome = ready.outcome
1670
- Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
1489
+ environment.registry.mark_agent_execution_admission(
1671
1490
  @agent.agent_id,
1672
1491
  execution_id: operation.execution_id,
1673
1492
  state: :suspended
@@ -1684,43 +1503,43 @@ module Phronomy
1684
1503
  outcome.result
1685
1504
  )
1686
1505
  Array(state&.invocation&.config&.fetch(:phronomy_exact_observers, [])).each do |task|
1687
- task.fail(Phronomy::ExecutionRehydrationRequiredError.new("Execution #{operation.execution_id} requires approval"))
1506
+ fail_task(task, Phronomy::ExecutionRehydrationRequiredError.new("Execution #{operation.execution_id} requires approval"))
1688
1507
  end
1689
1508
  end
1690
1509
 
1691
- def deliver_completed_execution_on_event_loop(ready, state, event_loop)
1510
+ def deliver_completed_execution_on_event_loop(ready, state, environment)
1692
1511
  operation = ready.operation
1693
1512
  delivery = ready.delivery
1694
1513
  outcome = ready.outcome
1695
- release_terminal_ownership(event_loop, operation.execution_id, state)
1514
+ release_terminal_ownership(environment, operation.execution_id, state)
1696
1515
  callback_error = deliver_terminal(delivery.application_listener, :done, outcome.result)
1697
1516
  settle_execution_waiters(
1698
- event_loop, operation.execution_id, delivery.result_task,
1517
+ environment, operation.execution_id, delivery.result_task,
1699
1518
  callback_error, :done, outcome.result
1700
1519
  )
1701
1520
  end
1702
1521
 
1703
- def deliver_handoff_on_event_loop(ready, state, event_loop)
1522
+ def deliver_handoff_on_event_loop(ready, state, environment)
1704
1523
  operation = ready.operation
1705
1524
  delivery = ready.delivery
1706
1525
  outcome = ready.outcome
1707
- release_terminal_ownership(event_loop, operation.execution_id, state)
1526
+ release_terminal_ownership(environment, operation.execution_id, state)
1708
1527
  result = outcome.result.merge(
1709
1528
  handoff_request: delivery.handoff_request,
1710
1529
  _phronomy_handoff_manifest: delivery.handoff_manifest
1711
1530
  ).freeze
1712
1531
  callback_error = deliver_terminal(delivery.application_listener, :handoff, result)
1713
1532
  settle_execution_waiters(
1714
- event_loop, operation.execution_id, delivery.result_task,
1533
+ environment, operation.execution_id, delivery.result_task,
1715
1534
  callback_error, :handoff, result
1716
1535
  )
1717
1536
  end
1718
1537
 
1719
- def deliver_failed_execution_on_event_loop(ready, state, event_loop)
1538
+ def deliver_failed_execution_on_event_loop(ready, state, environment)
1720
1539
  operation = ready.operation
1721
1540
  delivery = ready.delivery
1722
1541
  outcome = ready.outcome
1723
- release_terminal_ownership(event_loop, operation.execution_id, state)
1542
+ release_terminal_ownership(environment, operation.execution_id, state)
1724
1543
  type = terminal_event_type(outcome.error)
1725
1544
  callback_error = deliver_terminal(
1726
1545
  delivery.application_listener,
@@ -1728,13 +1547,13 @@ module Phronomy
1728
1547
  error: outcome.error
1729
1548
  )
1730
1549
  settle_execution_waiters(
1731
- event_loop, operation.execution_id, delivery.result_task,
1550
+ environment, operation.execution_id, delivery.result_task,
1732
1551
  callback_error, type, nil, outcome.error
1733
1552
  )
1734
1553
  end
1735
1554
 
1736
- def release_terminal_ownership(event_loop, execution_id, state)
1737
- registry = Phronomy::Agent::ExecutionRegistry.for(event_loop)
1555
+ def release_terminal_ownership(environment, execution_id, state)
1556
+ registry = environment.registry
1738
1557
  registry.release_agent_execution(execution_id) if state
1739
1558
  registry.release_agent_execution_admission(@agent.agent_id, execution_id: execution_id)
1740
1559
  end
@@ -1749,16 +1568,16 @@ module Phronomy
1749
1568
  expected_execution_revision:,
1750
1569
  expected_fsm_state:
1751
1570
  )
1752
- event_loop = Phronomy::Runtime.instance.event_loop
1753
- state = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(execution_id)
1571
+ environment = @agent.__execution_environment
1572
+ state = environment.registry.agent_execution_state(execution_id)
1754
1573
  authoritative = state &&
1755
1574
  state.agent.equal?(@agent) &&
1756
1575
  state.execution.execution_revision == expected_execution_revision &&
1757
1576
  state.fsm_session_id.to_s == fsm_session_id.to_s &&
1758
- event_loop.fsm_session_state(fsm_session_id) == expected_fsm_state
1577
+ environment.session_phase(fsm_session_id) == expected_fsm_state
1759
1578
  return state if authoritative
1760
1579
 
1761
- Phronomy.configuration.logger&.warn(
1580
+ Phronomy::RuntimeSettings.current.logger&.warn(
1762
1581
  "[Phronomy] Dropped stale Agent operation result: " \
1763
1582
  "execution_id=#{execution_id} fsm_session_id=#{fsm_session_id}"
1764
1583
  )
@@ -1777,14 +1596,14 @@ module Phronomy
1777
1596
  end
1778
1597
 
1779
1598
  def apply_agent_live_state(root:, appended_records:)
1780
- event_loop = Phronomy::Runtime.instance.event_loop
1781
- assert_event_loop!(event_loop)
1599
+ environment = @agent.__execution_environment
1600
+ assert_event_loop!(environment)
1782
1601
  @agent.send(:_append_journal_records, appended_records)
1783
1602
  @agent.__replace_root(root)
1784
1603
  end
1785
1604
 
1786
- def assert_event_loop!(event_loop)
1787
- return if event_loop.current?
1605
+ def assert_event_loop!(environment)
1606
+ return if environment.executing?
1788
1607
 
1789
1608
  raise Phronomy::Error,
1790
1609
  "ExecutionCoordinator live-state apply must run on EventLoop"
@@ -1803,20 +1622,26 @@ module Phronomy
1803
1622
  def dispatch_approval_listener(listener, request)
1804
1623
  return unless listener
1805
1624
 
1806
- Phronomy::Runtime.instance.offload.submit(on_full: :raise) do
1625
+ Phronomy::Blocking.call_async do
1807
1626
  listener.call(request)
1627
+ end.on_complete do |_value, error|
1628
+ report_approval_dispatch_failure(error) if error
1808
1629
  end
1809
1630
  rescue => error
1810
- Phronomy.configuration.logger&.warn(
1631
+ report_approval_dispatch_failure(error)
1632
+ end
1633
+
1634
+ def report_approval_dispatch_failure(error)
1635
+ Phronomy::RuntimeSettings.current.logger&.warn(
1811
1636
  "[Phronomy] approval listener dispatch failed: #{error.class}: #{error.message}"
1812
1637
  )
1813
1638
  end
1814
1639
 
1815
1640
  def settle_execution_waiters(
1816
- event_loop, execution_id, fallback_task, callback_error, event_type,
1641
+ environment, execution_id, fallback_task, callback_error, event_type,
1817
1642
  result, execution_error = nil
1818
1643
  )
1819
- waiters = Phronomy::Agent::ExecutionRegistry.for(event_loop).take_agent_completion_waiters(
1644
+ waiters = environment.registry.take_agent_completion_waiters(
1820
1645
  execution_id,
1821
1646
  fallback: fallback_task
1822
1647
  )
@@ -1835,7 +1660,7 @@ module Phronomy
1835
1660
  callback_error,
1836
1661
  event: StreamEvent.new(type: event_type, payload: result),
1837
1662
  execution_id: result&.fetch(:execution_id, nil),
1838
- callback_error_policy: Phronomy.configuration.stream_callback_error_policy
1663
+ callback_error_policy: Phronomy::Agent::Settings.current.stream_callback_error_policy
1839
1664
  )
1840
1665
  end
1841
1666
 
@@ -1847,7 +1672,7 @@ module Phronomy
1847
1672
  execution_error = nil
1848
1673
  )
1849
1674
  if callback_error
1850
- policy = Phronomy.configuration.stream_callback_error_policy
1675
+ policy = Phronomy::Agent::Settings.current.stream_callback_error_policy
1851
1676
  @agent.send(
1852
1677
  :_report_stream_callback_error,
1853
1678
  callback_error,
@@ -1872,6 +1697,7 @@ module Phronomy
1872
1697
  end
1873
1698
  if execution_error
1874
1699
  if execution_error.is_a?(Phronomy::CancellationError)
1700
+ result_task.finish_operation! if result_task.respond_to?(:finish_operation!)
1875
1701
  result_task.cancel!(execution_error)
1876
1702
  else
1877
1703
  fail_task(result_task, execution_error)
@@ -1888,7 +1714,7 @@ module Phronomy
1888
1714
  :error
1889
1715
  end
1890
1716
 
1891
- def post_control(runtime, command)
1717
+ def post_control(environment, command)
1892
1718
  admission = command.is_a?(StartCommand) || command.is_a?(ResumeCommand)
1893
1719
  completion = case command
1894
1720
  when StartCommand, ResumeCommand then command.result_task
@@ -1897,7 +1723,7 @@ module Phronomy
1897
1723
  when TerminalCommitReady then command.delivery.result_task
1898
1724
  when DeferredTerminalCommand then command.result_task
1899
1725
  end
1900
- ExecutionRegistry.for(runtime.event_loop).post(command,
1726
+ environment.registry.post(command,
1901
1727
  admission: admission, completion: completion)
1902
1728
  rescue Phronomy::RuntimeShutdownError
1903
1729
  false
@@ -1909,10 +1735,6 @@ module Phronomy
1909
1735
  )
1910
1736
  end
1911
1737
 
1912
- def translated(error)
1913
- @agent.send(:_translated_error, error)
1914
- end
1915
-
1916
1738
  def complete_task(task, result)
1917
1739
  @agent.send(:_complete_result_task, task, result)
1918
1740
  end