phronomy 0.26.0 → 0.27.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 (304) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +4 -0
  4. data/VERIFY.sh +27 -27
  5. data/benchmark/bench_agent_invoke.rb +26 -22
  6. data/benchmark/bench_context_assembler.rb +4 -5
  7. data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
  8. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  9. data/docs/architecture/agent-context.md +4 -2
  10. data/docs/architecture/agent-transition-ownership.md +89 -0
  11. data/docs/architecture/before-llm-input.md +6 -0
  12. data/docs/architecture/context-management.md +30 -0
  13. data/docs/architecture/context-preparation-steps.md +90 -0
  14. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  15. data/docs/architecture/execution-metadata-and-values.md +80 -0
  16. data/docs/architecture/generator-verifier-ownership.md +111 -0
  17. data/docs/architecture/multi-agent-handoff.md +8 -2
  18. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  19. data/docs/architecture/persistence.md +27 -4
  20. data/docs/architecture/refactoring-closure.md +334 -0
  21. data/docs/architecture/remaining-refactoring-plan.md +374 -0
  22. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  23. data/docs/architecture/tool-schema-recording-gap.md +50 -0
  24. data/docs/architecture/tracing.md +1 -1
  25. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  26. data/docs/architecture.md +209 -0
  27. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  28. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  29. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  30. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  31. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
  32. data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
  33. data/docs/decisions/032-storage-backend-composition.md +80 -0
  34. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  35. data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
  36. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  37. data/docs/decisions/036-context-contract-ownership.md +86 -0
  38. data/docs/decisions/037-common-definition-ownership.md +62 -0
  39. data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
  40. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
  41. data/docs/decisions/040-configuration-default-composition.md +94 -0
  42. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  43. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  44. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  45. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  46. data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
  47. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  48. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  49. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  50. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  51. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  52. data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
  53. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  54. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  55. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  56. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  57. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  58. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  59. data/docs/decisions/058-neutral-storage-primitives.md +78 -0
  60. data/docs/decisions/README.md +35 -6
  61. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  62. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  63. data/docs/features.md +9 -3
  64. data/docs/getting-started.md +4 -4
  65. data/docs/migrations/0.15.md +5 -0
  66. data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
  67. data/docs/migrations/handoff-runner-multi-agent.md +35 -0
  68. data/docs/migrations/neutral-storage-spi.md +43 -0
  69. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  70. data/docs/migrations/shared-state-multi-agent.md +44 -0
  71. data/docs/migrations/storage-backend-composition.md +117 -0
  72. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  73. data/docs/persistence-backends.md +162 -204
  74. data/docs/runtime-and-concurrency.md +117 -32
  75. data/lib/phronomy/agent/api/agent.rb +17 -0
  76. data/lib/phronomy/agent/async_event_api.rb +2 -2
  77. data/lib/phronomy/agent/base.rb +51 -241
  78. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  79. data/lib/phronomy/agent/context/capability/base.rb +67 -26
  80. data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
  81. data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
  82. data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
  83. data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
  84. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
  85. data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
  86. data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
  87. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
  88. data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
  89. data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
  90. data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
  91. data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
  92. data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
  93. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  94. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
  95. data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
  96. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  97. data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
  98. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
  99. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
  100. data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
  101. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  102. data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
  103. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
  104. data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
  105. data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
  106. data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
  107. data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
  108. data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
  109. data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
  110. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  111. data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
  112. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
  113. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
  114. data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
  115. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  116. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  117. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  118. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  119. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  120. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
  121. data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
  122. data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
  123. data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
  124. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
  125. data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
  126. data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
  127. data/lib/phronomy/agent/persistence/codec.rb +358 -0
  128. data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
  129. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
  130. data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
  131. data/lib/phronomy/agent/persistence/queries.rb +61 -0
  132. data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
  133. data/lib/phronomy/agent/persistence/watermark.rb +27 -0
  134. data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
  135. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
  136. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
  137. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
  138. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
  139. data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
  140. data/lib/phronomy/agent/selection/candidate.rb +1 -1
  141. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  142. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  143. data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
  144. data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
  145. data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
  146. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
  147. data/lib/phronomy/common/configuration_error.rb +7 -0
  148. data/lib/phronomy/common/error.rb +5 -0
  149. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  150. data/lib/phronomy/common/values/serializable.rb +32 -0
  151. data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
  152. data/lib/phronomy/configuration/global_configuration.rb +26 -0
  153. data/lib/phronomy/content_store/storage_schema.rb +11 -0
  154. data/lib/phronomy/content_store/stored_contents.rb +43 -0
  155. data/lib/phronomy/engine/backpressure_error.rb +7 -0
  156. data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
  157. data/lib/phronomy/engine/cancellation_error.rb +7 -0
  158. data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
  159. data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
  160. data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
  161. data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
  162. data/lib/phronomy/engine/event_loop.rb +158 -624
  163. data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
  164. data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
  165. data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
  166. data/lib/phronomy/engine/execution_receiver.rb +65 -0
  167. data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
  168. data/lib/phronomy/engine/fsm_protocol.rb +14 -0
  169. data/lib/phronomy/engine/fsm_session.rb +35 -28
  170. data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
  171. data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
  172. data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
  173. data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
  174. data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
  175. data/lib/phronomy/engine/runtime.rb +80 -84
  176. data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
  177. data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
  178. data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
  179. data/lib/phronomy/engine/task_result.rb +4 -0
  180. data/lib/phronomy/engine/timeout_error.rb +7 -0
  181. data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
  182. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  183. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  184. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  185. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  186. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  187. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  188. data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
  189. data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
  190. data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
  191. data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
  192. data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
  193. data/lib/phronomy/llm_contract/transport_error.rb +7 -0
  194. data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
  195. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
  196. data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
  197. data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
  198. data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
  199. data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
  200. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
  201. data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
  202. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  203. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
  204. data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
  205. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  206. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
  207. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  208. data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
  209. data/lib/phronomy/persistence/api/persistence.rb +140 -0
  210. data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
  211. data/lib/phronomy/persistence_composition/repositories.rb +77 -0
  212. data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
  213. data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
  214. data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
  215. data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
  216. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  217. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  218. data/lib/phronomy/storage/backend.rb +101 -0
  219. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  220. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  221. data/lib/phronomy/storage/blobs.rb +31 -0
  222. data/lib/phronomy/storage/condition.rb +25 -0
  223. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  224. data/lib/phronomy/storage/conflict_error.rb +9 -0
  225. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  226. data/lib/phronomy/storage/entry.rb +33 -0
  227. data/lib/phronomy/storage/guard_ref.rb +13 -0
  228. data/lib/phronomy/storage/not_found_error.rb +9 -0
  229. data/lib/phronomy/storage/record_codec.rb +177 -0
  230. data/lib/phronomy/storage/records.rb +61 -0
  231. data/lib/phronomy/storage/resource.rb +126 -0
  232. data/lib/phronomy/storage/scope.rb +25 -0
  233. data/lib/phronomy/storage/serialization_error.rb +9 -0
  234. data/lib/phronomy/storage/streams.rb +44 -0
  235. data/lib/phronomy/storage/transaction_error.rb +10 -0
  236. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  237. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  238. data/lib/phronomy/storage/validation.rb +53 -0
  239. data/lib/phronomy/storage/view.rb +131 -0
  240. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  241. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
  242. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
  243. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
  244. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
  245. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
  246. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
  247. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  248. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
  249. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  250. data/lib/phronomy/tool/contract/tool_error.rb +7 -0
  251. data/lib/phronomy/tools/agent.rb +1 -1
  252. data/lib/phronomy/version.rb +1 -1
  253. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
  254. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
  255. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  256. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
  257. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
  258. data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
  259. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  260. data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
  261. data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
  262. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
  263. data/lib/phronomy.rb +52 -94
  264. data/scripts/api_snapshot.rb +1 -1
  265. data/scripts/storage_spi_snapshot.rb +36 -0
  266. data/sig/phronomy/agent.rbs +0 -1
  267. data/sig/phronomy/execution_receiver.rbs +34 -0
  268. data/sig/phronomy/handoff.rbs +4 -2
  269. data/sig/phronomy/multi_agent.rbs +18 -0
  270. data/sig/phronomy/persistence.rbs +7 -91
  271. data/sig/phronomy/storage.rbs +174 -0
  272. data/sig/phronomy/tool.rbs +10 -1
  273. metadata +230 -99
  274. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  275. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  276. data/lib/phronomy/agent/recovery_support.rb +0 -504
  277. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  278. data/lib/phronomy/agent/tool_executor.rb +0 -55
  279. data/lib/phronomy/generator_verifier.rb +0 -369
  280. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  281. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  282. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  283. data/lib/phronomy/persistence/in_memory.rb +0 -690
  284. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  285. data/lib/phronomy/persistence.rb +0 -276
  286. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  287. data/lib/phronomy/workflow_recovery.rb +0 -123
  288. /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
  289. /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
  290. /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
  291. /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
  292. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  293. /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
  294. /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
  295. /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
  296. /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
  297. /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
  298. /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
  299. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  300. /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
  301. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
  302. /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
  303. /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
  304. /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ module Persistence
6
+ # Read and assemble domain results; the public entry point owns the execution-thread guard.
7
+ # @api private
8
+ class Queries
9
+ def initialize(repositories)
10
+ @repositories = repositories
11
+ end
12
+
13
+ def execution_result(execution_id)
14
+ execution = @repositories.executions.load(execution_id)
15
+ {
16
+ execution_id: execution.execution_id, agent_id: execution.agent_id,
17
+ status: execution.status, phase: execution.phase,
18
+ result_ref: execution.result_ref, error_ref: execution.error_ref,
19
+ result: execution.result_ref && @repositories.contents.fetch_text(execution.result_ref),
20
+ error: execution.error_ref && @repositories.contents.fetch_json(execution.error_ref)
21
+ }.then { |value| Phronomy::Values::Immutable.copy(value) }
22
+ end
23
+
24
+ def handoff_result(execution_id, main_agent_id: nil)
25
+ anchor = main_agent_id&.to_s
26
+ seen = {}
27
+ current = execution_id.to_s
28
+ reserved_agent_id = nil
29
+ loop do
30
+ raise Phronomy::Storage::SerializationError, "Cyclic durable Handoff chain" if seen[current]
31
+ seen[current] = true
32
+ begin
33
+ execution = @repositories.executions.load(current)
34
+ rescue Phronomy::Storage::NotFoundError
35
+ routing = @repositories.handoff_states.load(anchor)
36
+ if routing && Array(routing.metadata["cancelled_execution_ids"]).include?(current)
37
+ return {execution_id: current, agent_id: reserved_agent_id, status: :cancelled, result: nil, error: nil}.freeze
38
+ end
39
+ if reserved_agent_id && routing && routing.phase != "stable" && routing.pending_target_execution_id == current
40
+ return {execution_id: current, agent_id: reserved_agent_id, status: :active,
41
+ phase: :target_pending, reserved: true, result: nil, error: nil}.freeze
42
+ end
43
+ raise
44
+ end
45
+ anchor ||= execution.metadata.dig("coordination", "main_agent_id")
46
+ unless anchor && execution.metadata.dig("coordination", "main_agent_id") == anchor
47
+ raise Phronomy::Storage::ConflictError, "Execution does not belong to this Handoff anchor"
48
+ end
49
+ return @repositories.execution_result(current) unless execution.status == :handed_off
50
+ reserved_agent_id = execution.metadata.fetch("handoff_target_agent_id")
51
+ current = execution.metadata.fetch("handoff_target_execution_id")
52
+ end
53
+ end
54
+
55
+ def list_executions(agent_id, after: nil, limit: 100)
56
+ @repositories.executions.list(agent_id, after: after, limit: limit)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ module Persistence
6
+ # Domain-owned metadata; storage never interprets the record payload.
7
+ # @api private
8
+ module StorageSchema
9
+ ROOTS = Phronomy::Storage::Resource.new(id: "agent.roots", kind: :records,
10
+ guard: {resource: "agent.roots", via: :key})
11
+ EXECUTIONS = Phronomy::Storage::Resource.new(id: "agent.executions", kind: :records,
12
+ attributes: {owner: :string, active: :boolean}, immutable_attributes: [:owner],
13
+ indexes: {owner: [:owner], owner_active: [:owner, :active]},
14
+ unique: [{name: :one_active_owner, fields: [:owner], where: {active: true}}],
15
+ guard: {resource: ROOTS.id, via: :owner})
16
+
17
+ JOURNAL = Phronomy::Storage::Resource.new(id: "agent.journal", kind: :streams,
18
+ guard: {resource: ROOTS.id, via: :stream})
19
+ HANDOFF_STATES = Phronomy::Storage::Resource.new(id: "handoff.states", kind: :records,
20
+ attributes: {active_agent_id: :string})
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ module Persistence
6
+ # Agent revision and journal position form one guarded domain watermark.
7
+ # @api private
8
+ class Watermark
9
+ def initialize(view) = @view = view
10
+
11
+ def check!(agent_id:, agent_revision:, journal_position:)
12
+ key = agent_id.to_s
13
+ @view.check!(guards: [Phronomy::Storage::GuardRef.new(resource: StorageSchema::ROOTS, key: key)],
14
+ conditions: [
15
+ Phronomy::Storage::Condition::RevisionIs.new(resource: StorageSchema::ROOTS,
16
+ key: key, expected: Integer(agent_revision)),
17
+ Phronomy::Storage::Condition::StreamHeadIs.new(resource: StorageSchema::JOURNAL,
18
+ stream: key, expected: Integer(journal_position))
19
+ ])
20
+ rescue Phronomy::Storage::ConditionFailedError => error
21
+ label = error.condition.is_a?(Phronomy::Storage::Condition::RevisionIs) ? "agent revision" : "journal position"
22
+ raise Phronomy::Storage::ConflictError, "#{label} conflict"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Reconstructs operation-local live objects from already materialized facts.
6
+ # Persistence reads stay with SavedContextReader and the recovery preparer.
7
+ # @api private
8
+ module InvocationRestorer
9
+ module_function
10
+
11
+ def build_invocation_for_suspended(agent, execution, projection, main_coordinator, listener, assistant_message:)
12
+ request = execution.approval_request && Phronomy::Agent::ToolApprovalRequest.from_h(
13
+ execution.approval_request
14
+ )
15
+ assistant_record = SavedContextReader.latest_assistant_record(execution)
16
+ unless assistant_record
17
+ raise Phronomy::ExecutionRehydrationRequiredError,
18
+ "suspended execution #{execution.execution_id} has no durable assistant Tool Call message"
19
+ end
20
+
21
+ invocation, chat, config = prepare_invocation(agent, execution, projection, main_coordinator, listener)
22
+ chat.messages << assistant_message
23
+
24
+ invocation.chat = chat
25
+ invocation.user_message_sent = true
26
+ invocation.approval_request = request
27
+ invocation.instance_variable_set(
28
+ :@tool_batch_llm_call_id,
29
+ assistant_record.llm_call_id&.to_s
30
+ )
31
+
32
+ by_id = (request ? request.items : []).to_h do |item|
33
+ [item.tool_invocation_id.to_s, item]
34
+ end
35
+ snapshots = Array(execution.metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY])
36
+ if snapshots.empty?
37
+ raise Phronomy::ExecutionRehydrationRequiredError,
38
+ "suspended execution #{execution.execution_id} predates the durable Tool batch snapshot"
39
+ end
40
+
41
+ calls_by_id = if assistant_message.tool_calls.respond_to?(:values)
42
+ assistant_message.tool_calls.values.to_h do |call|
43
+ [call.id.to_s, call]
44
+ end
45
+ else
46
+ Array(assistant_message.tool_calls).to_h do |call|
47
+ [call.id.to_s, call]
48
+ end
49
+ end
50
+
51
+ children = snapshots.map do |snapshot|
52
+ entry = snapshot.to_h { |key, value| [key.to_s, value] }
53
+ call = calls_by_id.fetch(entry.fetch("tool_call_id").to_s) do
54
+ raise Phronomy::ExecutionRehydrationRequiredError,
55
+ "Tool Call #{entry.fetch("tool_call_id")} is missing from the durable assistant message"
56
+ end
57
+ tool = chat.tools[entry.fetch("tool_name").to_sym]
58
+ child = if tool
59
+ Phronomy::Agent::ToolInvocation.new(
60
+ execution_id: execution.execution_id,
61
+ agent: agent,
62
+ tool: tool,
63
+ tool_call: call,
64
+ config: config,
65
+ id: entry.fetch("tool_invocation_id")
66
+ )
67
+ else
68
+ Phronomy::Agent::ToolInvocation.missing(
69
+ execution_id: execution.execution_id,
70
+ agent: agent,
71
+ tool_call: call,
72
+ config: config,
73
+ id: entry.fetch("tool_invocation_id")
74
+ )
75
+ end
76
+ child.restore_state!(
77
+ status: entry.fetch("status").to_sym,
78
+ result: entry["result"],
79
+ approval_item: by_id[child.id.to_s]
80
+ )
81
+ end
82
+ invocation.tool_invocations = children
83
+ invocation
84
+ end
85
+
86
+ def build_chat_for_recovery(agent, execution, projection, main_coordinator, listener, messages:)
87
+ invocation, chat = prepare_invocation(agent, execution, projection, main_coordinator, listener)
88
+
89
+ messages.each { |message| chat.messages << message }
90
+
91
+ invocation.chat = chat
92
+ invocation.user_message_sent = true
93
+ invocation
94
+ end
95
+
96
+ def prepare_invocation(agent, execution, projection, main_coordinator, listener)
97
+ config = {
98
+ execution_id: execution.execution_id,
99
+ phronomy_execution_coordinator: main_coordinator,
100
+ phronomy_runtime_projection: projection
101
+ }.merge(agent.__coordination_config)
102
+ config = agent.__invocation_config(config)
103
+ if execution.metadata["coordination_cancel_requested"]
104
+ config = config.merge(cancellation_token: Phronomy::Concurrency::CancellationToken.new.cancel!)
105
+ end
106
+ invocation = Phronomy::Agent::AgentInvocation.new(
107
+ agent: agent,
108
+ input: projection.ask_message,
109
+ config: config,
110
+ event_listener: listener,
111
+ mode: (execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] || "invoke").to_sym,
112
+ execution_id: execution.execution_id
113
+ )
114
+ chat = agent.send(:build_chat, model_config: projection.model_config)
115
+ agent.send(
116
+ :_apply_runtime_projection_to_chat,
117
+ chat,
118
+ projection,
119
+ invocation: invocation
120
+ )
121
+ if projection.ask_message
122
+ chat.messages << RubyLLM::Message.new(
123
+ role: :user,
124
+ content: projection.ask_message
125
+ )
126
+ end
127
+ [invocation, chat, config]
128
+ end
129
+ private_class_method :prepare_invocation
130
+ end
131
+ end
132
+ end
@@ -33,13 +33,13 @@ module Phronomy
33
33
  return if !suspended && %i[resolution_required failed_terminal].include?(action)
34
34
 
35
35
  unless projection
36
- _manifest, projection = RecoverySupport.materialize_projection(agent, execution.metadata.fetch("manifest_ref"))
36
+ _manifest, projection = SavedContextReader.materialize_projection(agent, execution.metadata.fetch("manifest_ref"))
37
37
  end
38
38
  records = execution.working_records.select { |record| %i[assistant_message tool_message].include?(record.kind.to_sym) }
39
39
  materializer = RubyLLMMaterializer.new(agent: agent, persistence: agent.persistence)
40
40
  messages = records.map { |record| materializer.materialize_journal_record(record) }.freeze
41
41
  assistant = messages.reverse.find { |message| message.role.to_sym == :assistant }
42
- output, usage = RecoverySupport.provider_output_and_usage(agent, execution) if execution.phase.to_sym == :recovery_provider_completed
42
+ output, usage = SavedContextReader.provider_output_and_usage(agent, execution) if execution.phase.to_sym == :recovery_provider_completed
43
43
  RecoveryMaterial.new(projection: projection, messages: messages,
44
44
  assistant_message: assistant, output: output, usage: usage)
45
45
  end
@@ -48,7 +48,7 @@ module Phronomy
48
48
  event_loop = @runtime.event_loop
49
49
  action = recovery_action(execution)
50
50
  if action == :resolution_required
51
- event_loop.mark_agent_execution_admission(agent.agent_id,
51
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(agent.agent_id,
52
52
  execution_id: execution.execution_id, state: :recovery_required)
53
53
  deliver_resolution_required(execution, coordination_recovery_descriptor(execution))
54
54
  completion.complete({execution_id: execution.execution_id,
@@ -59,16 +59,16 @@ module Phronomy
59
59
 
60
60
  observe_recovery_execution(completion, execution)
61
61
  main = agent.send(:execution_coordinator_for, agent.__coordination_config)
62
- projection = event_loop.agent_execution_state(execution.execution_id).runtime_projection
62
+ projection = Phronomy::Agent::ExecutionRegistry.for(event_loop).agent_execution_state(execution.execution_id).runtime_projection
63
63
  if action == :failed_terminal
64
64
  invocation = build_failed_recovery_invocation(execution, main)
65
65
  else
66
66
  projection = material.projection
67
67
  invocation = if action == :framework_tools
68
- RecoverySupport.build_invocation_for_suspended(agent, execution, projection, main,
68
+ InvocationRestorer.build_invocation_for_suspended(agent, execution, projection, main,
69
69
  agent.send(:_phronomy_event_listener), assistant_message: material.assistant_message)
70
70
  else
71
- RecoverySupport.build_chat_for_recovery(agent, execution, projection, main,
71
+ InvocationRestorer.build_chat_for_recovery(agent, execution, projection, main,
72
72
  agent.send(:_phronomy_event_listener), messages: material.messages)
73
73
  end
74
74
  if execution.phase.to_sym == :recovery_provider_completed
@@ -77,36 +77,25 @@ module Phronomy
77
77
  prepare_saved_provider_calls(execution, invocation, material.assistant_message) if action == :framework_calls
78
78
  end
79
79
 
80
- event_loop.replace_agent_execution(execution.execution_id, execution: execution,
81
- runtime_projection: projection, invocation: invocation, fsm_session_id: nil)
82
- if action == :failed_terminal
83
- failure = execution.metadata.dig(RecoverySupport::RECOVERY_METADATA_KEY, "failure") ||
80
+ error = if action == :failed_terminal
81
+ failure = execution.metadata.dig(ExecutionMetadata::RECOVERY_METADATA_KEY, "failure") ||
84
82
  {"class" => "Phronomy::Error", "message" => "Recovery-resolved failure"}
85
- main.send(:begin_terminal_commit_on_event_loop,
86
- event_loop.agent_execution_state(execution.execution_id), completion, invocation,
87
- RecoverySupport.error_from_failure(failure), fsm_session_id: nil)
88
- return
89
- end
90
-
91
- event_loop.mark_agent_execution_admission(agent.agent_id,
92
- execution_id: execution.execution_id, state: :executing)
93
- case action
94
- when :framework_tools
95
- event_loop.register_agent_completion_waiter(execution.execution_id, completion)
96
- main.send(:start_framework_tools_on_event_loop, execution.execution_id, completion)
97
- when :framework_calls, :output
98
- # Re-enter the ordinary FSM before output filtering so its failures
99
- # settle through the same durable terminal barrier as a live call.
100
- start_recovery_session(event_loop, main, execution, invocation, completion,
101
- resume_event: :llm_completed, resume_phase: :calling_llm)
102
- when :followup
103
- start_recovery_session(event_loop, main, execution, invocation, completion,
104
- resume_event: :state_completed, resume_phase: :recording_tool_results)
83
+ RecoverySupport.error_from_failure(failure)
105
84
  end
85
+ main.deliver_on_event_loop(ExecutionCoordinator::ContinueRecoveredCommand.new(
86
+ coordinator: main,
87
+ execution_id: execution.execution_id,
88
+ expected_execution_revision: execution.execution_revision,
89
+ continuation: action,
90
+ invocation: invocation,
91
+ runtime_projection: projection,
92
+ result_task: completion,
93
+ error: error
94
+ ))
106
95
  end
107
96
 
108
97
  def prepare_saved_provider_calls(execution, invocation, message)
109
- record = RecoverySupport.latest_assistant_record(execution)
98
+ record = SavedContextReader.latest_assistant_record(execution)
110
99
  calls = message.tool_calls.respond_to?(:values) ? message.tool_calls.values : Array(message.tool_calls)
111
100
  framework_calls = calls.select { |call| agent.__framework_call?(call.name) }
112
101
  if framework_calls.empty?
@@ -119,23 +108,10 @@ module Phronomy
119
108
  Phronomy::Agent::AgentInvocation.new(agent: agent, input: nil,
120
109
  config: {execution_id: execution.execution_id, phronomy_execution_coordinator: main},
121
110
  event_listener: agent.send(:_phronomy_event_listener),
122
- mode: (execution.metadata[RecoverySupport::INVOCATION_MODE_KEY] || "invoke").to_sym,
111
+ mode: (execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] || "invoke").to_sym,
123
112
  execution_id: execution.execution_id)
124
113
  end
125
114
 
126
- def start_recovery_session(event_loop, main, execution, invocation, completion, resume_event:, resume_phase:)
127
- session = AgentInvocationSessionBuilder.build_for_resume(agent_invocation: invocation,
128
- resume_event: resume_event, resume_phase: resume_phase, runtime: @runtime)
129
- event_loop.replace_agent_execution(execution.execution_id, invocation: invocation, fsm_session_id: session.id)
130
- event_loop.register_agent_completion_waiter(execution.execution_id, completion)
131
- source = Phronomy::TaskResult.deferred(name: "#{completion.name}-source")
132
- source.on_complete do |completed, error|
133
- main.send(:finish_on_event_loop, execution.execution_id, completion,
134
- completed || session.context, error, fsm_session_id: session.id)
135
- end
136
- event_loop.register(session, completion: source)
137
- end
138
-
139
115
  def deliver_resolution_required(execution, descriptor)
140
116
  unless descriptor
141
117
  raise Phronomy::ExecutionRehydrationRequiredError,
@@ -11,7 +11,7 @@ module Phronomy
11
11
  def framework_batch?(execution)
12
12
  return false unless %i[dispatching_tools resuming recovery_tools].include?(execution.phase.to_sym)
13
13
  return false if execution.status == :suspended
14
- entries = Array(execution.metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY])
14
+ entries = Array(execution.metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY])
15
15
  pending = entries.reject { |entry| %w[completed rejected failed cancelled].include?(entry.fetch("status")) }
16
16
  !pending.empty? && pending.all? do |entry|
17
17
  entry.fetch("status") == "authorized" && agent.__framework_tool_replayable?(entry.fetch("tool_name"))
@@ -23,13 +23,13 @@ module Phronomy
23
23
  # slots then resume through their normal Tool sessions.
24
24
  def coordination_recovery_descriptor(execution)
25
25
  metadata = execution.metadata.dup
26
- if metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY]
27
- metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY] = metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY].sort_by do |entry|
26
+ if metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY]
27
+ metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY] = metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY].sort_by do |entry|
28
28
  agent.__framework_tool_replayable?(entry.fetch("tool_name")) ? 1 : 0
29
29
  end
30
30
  end
31
- if (recovery = metadata[RecoverySupport::RECOVERY_METADATA_KEY]) && recovery["subjects"]
32
- metadata[RecoverySupport::RECOVERY_METADATA_KEY] = recovery.merge("subjects" => recovery["subjects"].sort_by do |entry|
31
+ if (recovery = metadata[ExecutionMetadata::RECOVERY_METADATA_KEY]) && recovery["subjects"]
32
+ metadata[ExecutionMetadata::RECOVERY_METADATA_KEY] = recovery.merge("subjects" => recovery["subjects"].sort_by do |entry|
33
33
  agent.__framework_tool_replayable?(entry.fetch("tool_name")) ? 1 : 0
34
34
  end)
35
35
  end
@@ -45,14 +45,14 @@ module Phronomy
45
45
  manifest = base_manifest = projection = nil
46
46
  if manifest_ref
47
47
  manifest, projection =
48
- RecoverySupport.materialize_projection(
48
+ SavedContextReader.materialize_projection(
49
49
  agent,
50
50
  manifest_ref
51
51
  )
52
52
  base_manifest = if base_ref.to_s == manifest_ref.to_s
53
53
  manifest
54
54
  else
55
- RecoverySupport.manifest_from_ref(agent, base_ref)
55
+ SavedContextReader.manifest_from_ref(agent, base_ref)
56
56
  end
57
57
  end
58
58
 
@@ -151,12 +151,12 @@ module Phronomy
151
151
  bound = false
152
152
  installed = false
153
153
 
154
- event_loop.admit_agent_execution(
154
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).admit_agent_execution(
155
155
  agent.agent_id,
156
156
  owner_token: command.owner_token
157
157
  )
158
158
  admitted = true
159
- event_loop.bind_agent_execution_admission(
159
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).bind_agent_execution_admission(
160
160
  agent.agent_id,
161
161
  owner_token: command.owner_token,
162
162
  execution_id: execution.execution_id
@@ -165,13 +165,13 @@ module Phronomy
165
165
 
166
166
  invocation = nil
167
167
  if execution.status == :suspended || execution.phase.to_sym == :resuming
168
- invocation = RecoverySupport.build_invocation_for_suspended(
168
+ invocation = InvocationRestorer.build_invocation_for_suspended(
169
169
  agent, execution, plan.projection, main, agent.send(:_phronomy_event_listener),
170
170
  assistant_message: plan.material.assistant_message
171
171
  )
172
172
  end
173
173
 
174
- event_loop.install_agent_execution(
174
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).install_agent_execution(
175
175
  execution_id: execution.execution_id,
176
176
  agent: agent,
177
177
  coordinator: main,
@@ -184,7 +184,7 @@ module Phronomy
184
184
  installed = true
185
185
 
186
186
  if execution.status == :suspended
187
- event_loop.mark_agent_execution_admission(
187
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
188
188
  agent.agent_id,
189
189
  execution_id: execution.execution_id,
190
190
  state: :suspended
@@ -215,7 +215,7 @@ module Phronomy
215
215
 
216
216
  case plan.classification.disposition
217
217
  when Phronomy::Recovery::RESOLUTION_REQUIRED
218
- event_loop.mark_agent_execution_admission(
218
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).mark_agent_execution_admission(
219
219
  agent.agent_id,
220
220
  execution_id: execution.execution_id,
221
221
  state: :recovery_required
@@ -260,7 +260,7 @@ module Phronomy
260
260
  # simplecov:disable
261
261
  if installed
262
262
  begin
263
- event_loop.release_agent_execution(
263
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution(
264
264
  execution.execution_id
265
265
  )
266
266
  rescue
@@ -270,7 +270,7 @@ module Phronomy
270
270
  if admitted
271
271
  if bound
272
272
  begin
273
- event_loop.release_agent_execution_admission(
273
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
274
274
  agent.agent_id,
275
275
  execution_id: execution&.execution_id
276
276
  )
@@ -279,7 +279,7 @@ module Phronomy
279
279
  end
280
280
  else
281
281
  begin
282
- event_loop.release_agent_execution_admission(
282
+ Phronomy::Agent::ExecutionRegistry.for(event_loop).release_agent_execution_admission(
283
283
  agent.agent_id,
284
284
  owner_token: command.owner_token
285
285
  )
@@ -300,7 +300,7 @@ module Phronomy
300
300
  execution_id: execution.execution_id,
301
301
  mode: (
302
302
  execution.metadata[
303
- RecoverySupport::INVOCATION_MODE_KEY
303
+ ExecutionMetadata::INVOCATION_MODE_KEY
304
304
  ] || "invoke"
305
305
  ).to_sym
306
306
  )
@@ -327,17 +327,13 @@ module Phronomy
327
327
  name: "agent-recovery-auto:#{execution.execution_id}"
328
328
  )
329
329
  observe_recovery_execution(internal_task, execution)
330
- event_loop.mark_agent_execution_admission(
331
- agent.agent_id,
330
+ main.deliver_on_event_loop(ExecutionCoordinator::RecoverPreparationCommand.new(
331
+ coordinator: main,
332
332
  execution_id: execution.execution_id,
333
- state: :executing
334
- )
335
- main.send(
336
- :start_initial_preparation_recovery_on_event_loop,
337
- execution,
338
- internal_task,
333
+ expected_execution_revision: execution.execution_revision,
334
+ result_task: internal_task,
339
335
  load_completion: completion
340
- )
336
+ ))
341
337
  when :resuming
342
338
  approved = execution.approval_request &&
343
339
  (
@@ -352,18 +348,17 @@ module Phronomy
352
348
  name: "agent-recovery-auto:#{execution.execution_id}"
353
349
  )
354
350
  observe_recovery_execution(internal_task, execution)
355
- event_loop.mark_agent_execution_admission(
356
- agent.agent_id,
351
+ state = ExecutionRegistry.for(event_loop).agent_execution_state(execution.execution_id)
352
+ main.deliver_on_event_loop(ExecutionCoordinator::ContinueRecoveredCommand.new(
353
+ coordinator: main,
357
354
  execution_id: execution.execution_id,
358
- state: :executing
359
- )
360
- main.send(
361
- :start_resume_on_event_loop,
362
- execution.execution_id,
363
- internal_task,
364
- approved: false,
365
- config: {}
366
- )
355
+ expected_execution_revision: execution.execution_revision,
356
+ continuation: :approval_rejection,
357
+ invocation: state.invocation,
358
+ runtime_projection: state.runtime_projection,
359
+ result_task: internal_task,
360
+ error: nil
361
+ ))
367
362
  completion.complete(agent)
368
363
  when :recovery_tools_completed, :recovery_provider_completed, :recovery_resolved_failed
369
364
  internal_task = Phronomy::TaskResult.deferred(name: "agent-recovery-auto:#{execution.execution_id}")