phronomy 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +92 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +13 -3
  6. data/VERIFY.sh +27 -27
  7. data/benchmark/bench_agent_invoke.rb +26 -47
  8. data/benchmark/bench_context_assembler.rb +17 -15
  9. data/benchmark/bench_regression.rb +1 -1
  10. data/benchmark/bench_tool_schema.rb +1 -1
  11. data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
  12. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  13. data/docs/architecture/agent-context.md +4 -2
  14. data/docs/architecture/agent-transition-ownership.md +13 -0
  15. data/docs/architecture/backend-groups.md +152 -0
  16. data/docs/architecture/before-llm-input.md +9 -3
  17. data/docs/architecture/context-management.md +31 -1
  18. data/docs/architecture/context-preparation-steps.md +90 -0
  19. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  20. data/docs/architecture/execution-abstraction-review.md +88 -0
  21. data/docs/architecture/execution-boundaries.md +28 -0
  22. data/docs/architecture/execution-metadata-and-values.md +86 -0
  23. data/docs/architecture/generator-verifier-ownership.md +111 -0
  24. data/docs/architecture/multi-agent-handoff.md +11 -4
  25. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  26. data/docs/architecture/persistence.md +45 -4
  27. data/docs/architecture/r8-unit1.md +104 -0
  28. data/docs/architecture/r8-unit10.md +72 -0
  29. data/docs/architecture/r8-unit11.md +71 -0
  30. data/docs/architecture/r8-unit12.md +67 -0
  31. data/docs/architecture/r8-unit13.md +61 -0
  32. data/docs/architecture/r8-unit14.md +72 -0
  33. data/docs/architecture/r8-unit15.md +65 -0
  34. data/docs/architecture/r8-unit16.md +54 -0
  35. data/docs/architecture/r8-unit17.md +73 -0
  36. data/docs/architecture/r8-unit18.md +92 -0
  37. data/docs/architecture/r8-unit19.md +61 -0
  38. data/docs/architecture/r8-unit2.md +55 -0
  39. data/docs/architecture/r8-unit20.md +51 -0
  40. data/docs/architecture/r8-unit21.md +79 -0
  41. data/docs/architecture/r8-unit22.md +74 -0
  42. data/docs/architecture/r8-unit23.md +81 -0
  43. data/docs/architecture/r8-unit3.md +130 -0
  44. data/docs/architecture/r8-unit4.md +79 -0
  45. data/docs/architecture/r8-unit5.md +115 -0
  46. data/docs/architecture/r8-unit6.md +71 -0
  47. data/docs/architecture/r8-unit7.md +70 -0
  48. data/docs/architecture/r8-unit8.md +78 -0
  49. data/docs/architecture/r8-unit9.md +73 -0
  50. data/docs/architecture/refactoring-closure.md +343 -0
  51. data/docs/architecture/remaining-refactoring-plan.md +390 -0
  52. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  53. data/docs/architecture/storage-execution-boundaries.md +54 -0
  54. data/docs/architecture/tool-schema-recording-gap.md +56 -0
  55. data/docs/architecture/tracing.md +2 -2
  56. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  57. data/docs/architecture.md +222 -0
  58. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  59. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  60. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  61. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  62. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  63. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  64. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
  65. data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
  66. data/docs/decisions/032-storage-backend-composition.md +85 -0
  67. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  68. data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
  69. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  70. data/docs/decisions/036-context-contract-ownership.md +86 -0
  71. data/docs/decisions/037-common-definition-ownership.md +62 -0
  72. data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
  73. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
  74. data/docs/decisions/040-configuration-default-composition.md +105 -0
  75. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  76. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  77. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  78. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  79. data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
  80. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  81. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  82. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  83. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  84. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  85. data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
  86. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  87. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  88. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  89. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  90. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  91. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  92. data/docs/decisions/058-neutral-storage-primitives.md +83 -0
  93. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  94. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  95. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  96. data/docs/decisions/062-content-store-service.md +52 -0
  97. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  98. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  99. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  100. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  101. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  102. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  103. data/docs/decisions/README.md +52 -6
  104. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  105. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  106. data/docs/execution-boundaries-preview.md +45 -0
  107. data/docs/features.md +16 -5
  108. data/docs/getting-started.md +11 -8
  109. data/docs/migrations/0.15.md +5 -0
  110. data/docs/migrations/0.22.md +2 -2
  111. data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
  112. data/docs/migrations/handoff-runner-multi-agent.md +37 -0
  113. data/docs/migrations/neutral-storage-spi.md +43 -0
  114. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  115. data/docs/migrations/persistence-failure-contracts.md +67 -0
  116. data/docs/migrations/r8-unit10.md +36 -0
  117. data/docs/migrations/r8-unit11.md +33 -0
  118. data/docs/migrations/r8-unit12.md +31 -0
  119. data/docs/migrations/r8-unit13.md +36 -0
  120. data/docs/migrations/r8-unit14.md +31 -0
  121. data/docs/migrations/r8-unit15.md +31 -0
  122. data/docs/migrations/r8-unit16.md +26 -0
  123. data/docs/migrations/r8-unit17.md +28 -0
  124. data/docs/migrations/r8-unit18.md +29 -0
  125. data/docs/migrations/r8-unit19.md +28 -0
  126. data/docs/migrations/r8-unit20.md +24 -0
  127. data/docs/migrations/r8-unit21.md +28 -0
  128. data/docs/migrations/r8-unit22.md +29 -0
  129. data/docs/migrations/r8-unit23.md +20 -0
  130. data/docs/migrations/r8-unit4.md +67 -0
  131. data/docs/migrations/r8-unit5.md +75 -0
  132. data/docs/migrations/r8-unit6.md +109 -0
  133. data/docs/migrations/r8-unit7.md +31 -0
  134. data/docs/migrations/r8-unit8.md +33 -0
  135. data/docs/migrations/r8-unit9.md +28 -0
  136. data/docs/migrations/shared-state-multi-agent.md +44 -0
  137. data/docs/migrations/storage-async-client.md +103 -0
  138. data/docs/migrations/storage-backend-composition.md +117 -0
  139. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  140. data/docs/migrations/vector-async-clients.md +110 -0
  141. data/docs/persistence-backends.md +190 -215
  142. data/docs/runtime-and-concurrency.md +142 -32
  143. data/lib/phronomy/agent/admission.rb +78 -0
  144. data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
  145. data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
  146. data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
  147. data/lib/phronomy/agent/api/agent.rb +17 -0
  148. data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
  149. data/lib/phronomy/agent/async_event_api.rb +38 -33
  150. data/lib/phronomy/agent/base.rb +106 -294
  151. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  152. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  153. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  154. data/lib/phronomy/agent/context_importer.rb +2 -2
  155. data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
  156. data/lib/phronomy/agent/control_request.rb +21 -0
  157. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  158. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
  159. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  160. data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
  161. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
  162. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
  163. data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
  164. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  165. data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
  166. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
  167. data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
  168. data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
  169. data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
  170. data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
  171. data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
  172. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  173. data/lib/phronomy/agent/execution_change.rb +161 -0
  174. data/lib/phronomy/agent/execution_environment.rb +36 -0
  175. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  176. data/lib/phronomy/agent/execution_observation.rb +35 -0
  177. data/lib/phronomy/agent/filterable.rb +182 -0
  178. data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
  179. data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
  180. data/lib/phronomy/agent/handoff_error.rb +7 -0
  181. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  182. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  183. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  184. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  185. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  186. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  187. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
  188. data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
  189. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  190. data/lib/phronomy/agent/persistence/codec.rb +338 -0
  191. data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
  192. data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
  193. data/lib/phronomy/agent/persistence/records.rb +33 -0
  194. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  195. data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
  196. data/lib/phronomy/agent/persistence/watermark.rb +29 -0
  197. data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
  198. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
  199. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
  200. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
  201. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
  202. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  203. data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
  204. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  205. data/lib/phronomy/agent/retention.rb +17 -0
  206. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  207. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  208. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  209. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  210. data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
  211. data/lib/phronomy/agent/saved_context_reader.rb +55 -0
  212. data/lib/phronomy/agent/settings.rb +47 -0
  213. data/lib/phronomy/agent/state_writer.rb +166 -0
  214. data/lib/phronomy/agent/store.rb +253 -0
  215. data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
  216. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  217. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  218. data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
  219. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
  220. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  221. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  222. data/lib/phronomy/common/configuration_error.rb +7 -0
  223. data/lib/phronomy/common/error.rb +5 -0
  224. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  225. data/lib/phronomy/common/values/serializable.rb +32 -0
  226. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  227. data/lib/phronomy/content_store/storage_schema.rb +12 -0
  228. data/lib/phronomy/content_store/stored_contents.rb +44 -0
  229. data/lib/phronomy/context/assembly.rb +202 -0
  230. data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
  231. data/lib/phronomy/context/candidate.rb +51 -0
  232. data/lib/phronomy/context/constraint.rb +47 -0
  233. data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
  234. data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
  235. data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
  236. data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
  237. data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
  238. data/lib/phronomy/context/default_policy.rb +140 -0
  239. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  240. data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
  241. data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
  242. data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
  243. data/lib/phronomy/context/manifest_error.rb +10 -0
  244. data/lib/phronomy/context/prompt_template.rb +98 -0
  245. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  246. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  247. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  248. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  249. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  250. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  251. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  252. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  253. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  254. data/lib/phronomy/embeddings/base.rb +43 -0
  255. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  256. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  257. data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
  258. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  259. data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
  260. data/lib/phronomy/engine/event_loop.rb +164 -630
  261. data/lib/phronomy/engine/execution_binding.rb +23 -0
  262. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  263. data/lib/phronomy/engine/fsm_protocol.rb +9 -0
  264. data/lib/phronomy/engine/fsm_session.rb +37 -30
  265. data/lib/phronomy/engine/metrics.rb +28 -0
  266. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  267. data/lib/phronomy/engine/runtime.rb +104 -95
  268. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  269. data/lib/phronomy/execution/async_operation.rb +41 -0
  270. data/lib/phronomy/execution/backpressure_error.rb +7 -0
  271. data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
  272. data/lib/phronomy/execution/cancellation_error.rb +7 -0
  273. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
  274. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  275. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  276. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  277. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  278. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  279. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  280. data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
  281. data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
  282. data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
  283. data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
  284. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  285. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  286. data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
  287. data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
  288. data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
  289. data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
  290. data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
  291. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  292. data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
  293. data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
  294. data/lib/phronomy/execution/runnable.rb +24 -0
  295. data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
  296. data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
  297. data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
  298. data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
  299. data/lib/phronomy/execution/timeout_error.rb +7 -0
  300. data/lib/phronomy/execution/wait_policy.rb +24 -0
  301. data/lib/phronomy/filter/filter_block_error.rb +14 -0
  302. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  303. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  304. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  305. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  306. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  307. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  308. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  309. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  310. data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
  311. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  312. data/lib/phronomy/llm_adapter/base.rb +49 -68
  313. data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
  314. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  315. data/lib/phronomy/llm_adapter/message.rb +62 -0
  316. data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
  317. data/lib/phronomy/llm_adapter/request.rb +79 -0
  318. data/lib/phronomy/llm_adapter/response.rb +36 -0
  319. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  320. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  321. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  322. data/lib/phronomy/llm_adapter.rb +3 -16
  323. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  324. data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
  325. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  326. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  327. data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
  328. data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
  329. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  330. data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
  331. data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
  332. data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
  333. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  334. data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
  335. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  336. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  337. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  338. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
  339. data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
  340. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  341. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  342. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  343. data/lib/phronomy/multi_agent/store.rb +156 -0
  344. data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
  345. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  346. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
  347. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  348. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  349. data/lib/phronomy/persistence/content_repository.rb +26 -0
  350. data/lib/phronomy/persistence/errors.rb +16 -0
  351. data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
  352. data/lib/phronomy/persistence/persistence.rb +23 -0
  353. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  354. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  355. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  356. data/lib/phronomy/persistence/transaction.rb +86 -0
  357. data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
  358. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  359. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  360. data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
  361. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  362. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  363. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  364. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  365. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  366. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  367. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  368. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  369. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  370. data/lib/phronomy/storage/async/async_client.rb +60 -0
  371. data/lib/phronomy/storage/backend.rb +107 -0
  372. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  373. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  374. data/lib/phronomy/storage/blobs.rb +31 -0
  375. data/lib/phronomy/storage/condition.rb +25 -0
  376. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  377. data/lib/phronomy/storage/conflict_error.rb +9 -0
  378. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  379. data/lib/phronomy/storage/entry.rb +33 -0
  380. data/lib/phronomy/storage/guard_ref.rb +13 -0
  381. data/lib/phronomy/storage/not_found_error.rb +9 -0
  382. data/lib/phronomy/storage/record_codec.rb +177 -0
  383. data/lib/phronomy/storage/records.rb +61 -0
  384. data/lib/phronomy/storage/resource.rb +126 -0
  385. data/lib/phronomy/storage/scope.rb +25 -0
  386. data/lib/phronomy/storage/serialization_error.rb +9 -0
  387. data/lib/phronomy/storage/streams.rb +44 -0
  388. data/lib/phronomy/storage/transaction_error.rb +10 -0
  389. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  390. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  391. data/lib/phronomy/storage/validation.rb +53 -0
  392. data/lib/phronomy/storage/view.rb +131 -0
  393. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  394. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  395. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  396. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  397. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
  398. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
  399. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
  400. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  401. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
  402. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  403. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
  404. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  405. data/lib/phronomy/tool/authorization.rb +77 -0
  406. data/lib/phronomy/tool/base.rb +549 -9
  407. data/lib/phronomy/tool/call_request.rb +40 -0
  408. data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
  409. data/lib/phronomy/tool/operation.rb +88 -0
  410. data/lib/phronomy/tool/schema.rb +214 -0
  411. data/lib/phronomy/tool/settings.rb +31 -0
  412. data/lib/phronomy/tool/tool_error.rb +7 -0
  413. data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
  414. data/lib/phronomy/tools/agent.rb +22 -90
  415. data/lib/phronomy/tools/mcp.rb +21 -14
  416. data/lib/phronomy/tools/vector_search.rb +4 -4
  417. data/lib/phronomy/tracing/automatic.rb +11 -6
  418. data/lib/phronomy/tracing/base.rb +1 -1
  419. data/lib/phronomy/tracing/observation.rb +37 -0
  420. data/lib/phronomy/tracing/settings.rb +36 -0
  421. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  422. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  423. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  424. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  425. data/lib/phronomy/vector_store/base.rb +118 -49
  426. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  427. data/lib/phronomy/vector_store.rb +2 -17
  428. data/lib/phronomy/version.rb +1 -1
  429. data/lib/phronomy/workflow/completion.rb +11 -0
  430. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  431. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  432. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
  433. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  434. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  435. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
  436. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
  437. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  438. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  439. data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
  440. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  441. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  442. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  443. data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
  444. data/lib/phronomy.rb +97 -98
  445. data/scripts/api_snapshot.rb +36 -16
  446. data/scripts/storage_spi_snapshot.rb +36 -0
  447. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  448. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  449. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  450. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  451. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  452. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  453. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  454. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  455. data/sig/phronomy/agent/admission.rbs +19 -0
  456. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  457. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  458. data/sig/phronomy/agent/store.rbs +73 -0
  459. data/sig/phronomy/agent.rbs +14 -139
  460. data/sig/phronomy/common.rbs +7 -0
  461. data/sig/phronomy/content_store/contracts.rbs +13 -0
  462. data/sig/phronomy/context.rbs +152 -0
  463. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  464. data/sig/phronomy/embeddings/base.rbs +17 -0
  465. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  466. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  467. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  468. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  469. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  470. data/sig/phronomy/engine/observability.rbs +13 -0
  471. data/sig/phronomy/execution/async_operation.rbs +7 -0
  472. data/sig/phronomy/execution/blocking.rbs +5 -0
  473. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  474. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  475. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  476. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  477. data/sig/phronomy/execution/errors.rbs +7 -0
  478. data/sig/phronomy/execution/execution.rbs +41 -0
  479. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  480. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  481. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  482. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  483. data/sig/phronomy/execution/task_result.rbs +29 -0
  484. data/sig/phronomy/extensions.rbs +0 -21
  485. data/sig/phronomy/handoff.rbs +12 -4
  486. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  487. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  488. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  489. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  490. data/sig/phronomy/llm_context_window.rbs +10 -0
  491. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  492. data/sig/phronomy/multi_agent/store.rbs +54 -0
  493. data/sig/phronomy/multi_agent.rbs +24 -3
  494. data/sig/phronomy/persistence/errors.rbs +18 -0
  495. data/sig/phronomy/persistence/migration.rbs +13 -0
  496. data/sig/phronomy/persistence/transaction.rbs +19 -0
  497. data/sig/phronomy/persistence.rbs +3 -185
  498. data/sig/phronomy/persistence_composition.rbs +19 -0
  499. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  500. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  501. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  502. data/sig/phronomy/storage/contracts.rbs +160 -0
  503. data/sig/phronomy/tool.rbs +58 -5
  504. data/sig/phronomy/tracing/observation.rbs +7 -0
  505. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  506. data/sig/phronomy/vector_store/base.rbs +23 -0
  507. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  508. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  509. data/sig/phronomy/workflow/store.rbs +8 -0
  510. data/sig/phronomy/workflow.rbs +1 -1
  511. data/sig/phronomy.rbs +0 -49
  512. metadata +462 -130
  513. data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
  514. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  515. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  516. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  517. data/lib/phronomy/agent/context/capability/base.rb +0 -507
  518. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  519. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  520. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  521. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  522. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  523. data/lib/phronomy/agent/handoff_request.rb +0 -45
  524. data/lib/phronomy/agent/handoff_runner.rb +0 -178
  525. data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
  526. data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
  527. data/lib/phronomy/agent/recovery_support.rb +0 -504
  528. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  529. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  530. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  531. data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
  532. data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
  533. data/lib/phronomy/configuration.rb +0 -59
  534. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  535. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  536. data/lib/phronomy/generator_verifier.rb +0 -369
  537. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  538. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  539. data/lib/phronomy/metrics.rb +0 -26
  540. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  541. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  542. data/lib/phronomy/persistence/in_memory.rb +0 -690
  543. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  544. data/lib/phronomy/persistence.rb +0 -276
  545. data/lib/phronomy/recovery.rb +0 -186
  546. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  547. data/lib/phronomy/runnable.rb +0 -54
  548. data/lib/phronomy/token_usage.rb +0 -85
  549. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  550. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  551. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  552. data/lib/phronomy/workflow_recovery.rb +0 -123
  553. data/sig/phronomy/llm_adapter.rbs +0 -11
  554. data/sig/phronomy/runtime.rbs +0 -76
  555. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  556. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  557. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+
5
+ module Phronomy
6
+ module Agent
7
+ module Persistence
8
+ # @api private
9
+ class RetentionRepository
10
+ include Phronomy::Storage::RecordCodec
11
+
12
+ def initialize(view) = @view = view
13
+
14
+ def retain(retention)
15
+ Phronomy::Persistence::StorageBoundary.call do
16
+ @view.atomic do |view|
17
+ guard!(view, retention.agent_id)
18
+ records = view.records(StorageSchema::RETENTIONS)
19
+ key = Digest::SHA256.hexdigest(Phronomy::CanonicalJSON.dump(retention.to_h))
20
+ if (existing = records.read(key))
21
+ raise Phronomy::Storage::SerializationError, "retention identity mismatch" unless decode(existing) == retention
22
+ else
23
+ records.insert(key: key, revision: 0,
24
+ attributes: {owner: retention.agent_id, holder: retention.owner_key},
25
+ record: build_record("phronomy.agent_retention", "0.1", retention.to_h))
26
+ end
27
+ end
28
+ end
29
+ retention
30
+ end
31
+
32
+ def list(agent_id)
33
+ Phronomy::Persistence::StorageBoundary.call do
34
+ @view.atomic { |view| view.records(StorageSchema::RETENTIONS).scan(index: :owner, equals: {owner: agent_id}).map { |entry| decode(entry) }.freeze }
35
+ end
36
+ end
37
+
38
+ def release(agent_id:, owner_key:)
39
+ Phronomy::Persistence::StorageBoundary.call do
40
+ @view.atomic do |view|
41
+ guard!(view, agent_id)
42
+ records = view.records(StorageSchema::RETENTIONS)
43
+ records.scan(index: :owner, equals: {owner: agent_id}).each do |entry|
44
+ value = decode(entry)
45
+ records.delete(key: entry.key, expected_revision: entry.revision) if value.owner_key == owner_key
46
+ end
47
+ end
48
+ end
49
+ nil
50
+ end
51
+
52
+ private
53
+
54
+ def guard!(view, id)
55
+ view.check!(guards: [Phronomy::Storage::GuardRef.new(resource: StorageSchema::ROOTS, key: id)], conditions: [])
56
+ end
57
+
58
+ def decode(entry)
59
+ payload = current_payload!(entry.record, record_type: "phronomy.agent_retention", format_version: "0.1",
60
+ keys: %w[agent_id execution_id owner_key], label: "Agent retention")
61
+ value = Retention.new(**payload.transform_keys(&:to_sym))
62
+ unless entry.attributes == {owner: value.agent_id, holder: value.owner_key}
63
+ raise Phronomy::Storage::SerializationError, "retention attributes mismatch"
64
+ end
65
+ value
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
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
+ CANCELLATIONS = Phronomy::Storage::Resource.new(id: "agent.cancellations", kind: :records,
20
+ attributes: {owner: :string}, immutable_attributes: [:owner], indexes: {owner: [:owner]},
21
+ guard: {resource: ROOTS.id, via: :owner})
22
+ RETENTIONS = Phronomy::Storage::Resource.new(id: "agent.retentions", kind: :records,
23
+ attributes: {owner: :string, holder: :string}, immutable_attributes: [:owner, :holder],
24
+ indexes: {owner: [:owner], holder: [:holder]},
25
+ guard: {resource: ROOTS.id, via: :owner})
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
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
+ Phronomy::Persistence::StorageBoundary.call do
13
+ key = agent_id.to_s
14
+ @view.check!(guards: [Phronomy::Storage::GuardRef.new(resource: StorageSchema::ROOTS, key: key)],
15
+ conditions: [
16
+ Phronomy::Storage::Condition::RevisionIs.new(resource: StorageSchema::ROOTS,
17
+ key: key, expected: Integer(agent_revision)),
18
+ Phronomy::Storage::Condition::StreamHeadIs.new(resource: StorageSchema::JOURNAL,
19
+ stream: key, expected: Integer(journal_position))
20
+ ])
21
+ rescue Phronomy::Storage::ConditionFailedError => error
22
+ label = error.condition.is_a?(Phronomy::Storage::Condition::RevisionIs) ? "agent revision" : "journal position"
23
+ raise Phronomy::Storage::ConflictError, "#{label} conflict"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,124 @@
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:, cancellation_requested: false)
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, config = prepare_invocation(agent, execution, projection, main_coordinator, listener, cancellation_requested: cancellation_requested)
22
+ invocation.messages << assistant_message
23
+
24
+ invocation.user_message_sent = true
25
+ invocation.approval_request = request
26
+ invocation.instance_variable_set(
27
+ :@tool_batch_llm_call_id,
28
+ assistant_record.llm_call_id&.to_s
29
+ )
30
+
31
+ by_id = (request ? request.items : []).to_h do |item|
32
+ [item.tool_invocation_id.to_s, item]
33
+ end
34
+ snapshots = Array(execution.metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY])
35
+ if snapshots.empty?
36
+ raise Phronomy::ExecutionRehydrationRequiredError,
37
+ "suspended execution #{execution.execution_id} predates the durable Tool batch snapshot"
38
+ end
39
+
40
+ calls_by_id = if assistant_message.tool_calls.respond_to?(:values)
41
+ assistant_message.tool_calls.values.to_h do |call|
42
+ [call.id.to_s, call]
43
+ end
44
+ else
45
+ Array(assistant_message.tool_calls).to_h do |call|
46
+ [call.id.to_s, call]
47
+ end
48
+ end
49
+
50
+ children = snapshots.map do |snapshot|
51
+ entry = snapshot.to_h { |key, value| [key.to_s, value] }
52
+ call = calls_by_id.fetch(entry.fetch("tool_call_id").to_s) do
53
+ raise Phronomy::ExecutionRehydrationRequiredError,
54
+ "Tool Call #{entry.fetch("tool_call_id")} is missing from the durable assistant message"
55
+ end
56
+ tool = invocation.tools[entry.fetch("tool_name").to_sym]
57
+ child = if tool
58
+ Phronomy::Agent::ToolInvocation.new(
59
+ execution_id: execution.execution_id,
60
+ agent: agent,
61
+ tool: tool,
62
+ tool_call: call,
63
+ config: config,
64
+ id: entry.fetch("tool_invocation_id")
65
+ )
66
+ else
67
+ Phronomy::Agent::ToolInvocation.missing(
68
+ execution_id: execution.execution_id,
69
+ agent: agent,
70
+ tool_call: call,
71
+ config: config,
72
+ id: entry.fetch("tool_invocation_id")
73
+ )
74
+ end
75
+ child.restore_state!(
76
+ status: entry.fetch("status").to_sym,
77
+ result: entry["result"],
78
+ approval_item: by_id[child.id.to_s]
79
+ )
80
+ end
81
+ invocation.tool_invocations = children
82
+ invocation
83
+ end
84
+
85
+ def build_input_for_recovery(agent, execution, projection, main_coordinator, listener, messages:, cancellation_requested: false)
86
+ invocation, = prepare_invocation(agent, execution, projection, main_coordinator, listener, cancellation_requested: cancellation_requested)
87
+
88
+ messages.each { |message| invocation.messages << message }
89
+
90
+ invocation.user_message_sent = true
91
+ invocation
92
+ end
93
+
94
+ def prepare_invocation(agent, execution, projection, main_coordinator, listener, cancellation_requested:)
95
+ config = {
96
+ execution_id: execution.execution_id,
97
+ phronomy_execution_coordinator: main_coordinator,
98
+ phronomy_runtime_projection: projection
99
+ }.merge(agent.__execution_wiring)
100
+ config = agent.__invocation_config(config)
101
+ if cancellation_requested || execution.metadata["cancellation_requested"]
102
+ config = config.merge(cancellation_token: Phronomy::Concurrency::CancellationToken.new.cancel!)
103
+ end
104
+ invocation = Phronomy::Agent::AgentInvocation.new(
105
+ agent: agent,
106
+ input: projection.ask_message,
107
+ config: config,
108
+ event_listener: listener,
109
+ mode: (execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] || "invoke").to_sym,
110
+ execution_id: execution.execution_id
111
+ )
112
+ agent.send(:prepare_runtime_input, projection, invocation: invocation)
113
+ if projection.ask_message
114
+ invocation.messages << Phronomy::LLMAdapter::Message.new(
115
+ role: :user,
116
+ content: projection.ask_message
117
+ )
118
+ end
119
+ [invocation, config]
120
+ end
121
+ private_class_method :prepare_invocation
122
+ end
123
+ end
124
+ end
@@ -33,22 +33,23 @@ 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
- materializer = RubyLLMMaterializer.new(agent: agent, persistence: agent.persistence)
39
+ materializer = RuntimeInput.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
- assistant_message: assistant, output: output, usage: usage)
44
+ assistant_message: assistant, output: output, usage: usage,
45
+ cancellation_requested: agent.persistence.cancellation_requested?(agent_id: agent.agent_id, execution_id: execution.execution_id))
45
46
  end
46
47
 
47
48
  def continue_recovery_on_event_loop(execution, completion, material:)
48
- event_loop = @runtime.event_loop
49
+ environment = @environment
49
50
  action = recovery_action(execution)
50
51
  if action == :resolution_required
51
- event_loop.mark_agent_execution_admission(agent.agent_id,
52
+ environment.registry.mark_agent_execution_admission(agent.agent_id,
52
53
  execution_id: execution.execution_id, state: :recovery_required)
53
54
  deliver_resolution_required(execution, coordination_recovery_descriptor(execution))
54
55
  completion.complete({execution_id: execution.execution_id,
@@ -58,18 +59,18 @@ module Phronomy
58
59
  end
59
60
 
60
61
  observe_recovery_execution(completion, execution)
61
- main = agent.send(:execution_coordinator_for, agent.__coordination_config)
62
- projection = event_loop.agent_execution_state(execution.execution_id).runtime_projection
62
+ main = agent.send(:execution_coordinator_for, agent.__execution_wiring)
63
+ projection = environment.registry.agent_execution_state(execution.execution_id).runtime_projection
63
64
  if action == :failed_terminal
64
65
  invocation = build_failed_recovery_invocation(execution, main)
65
66
  else
66
67
  projection = material.projection
67
68
  invocation = if action == :framework_tools
68
- RecoverySupport.build_invocation_for_suspended(agent, execution, projection, main,
69
- agent.send(:_phronomy_event_listener), assistant_message: material.assistant_message)
69
+ InvocationRestorer.build_invocation_for_suspended(agent, execution, projection, main,
70
+ agent.send(:_phronomy_event_listener), assistant_message: material.assistant_message, cancellation_requested: material.cancellation_requested)
70
71
  else
71
- RecoverySupport.build_chat_for_recovery(agent, execution, projection, main,
72
- agent.send(:_phronomy_event_listener), messages: material.messages)
72
+ InvocationRestorer.build_input_for_recovery(agent, execution, projection, main,
73
+ agent.send(:_phronomy_event_listener), messages: material.messages, cancellation_requested: material.cancellation_requested)
73
74
  end
74
75
  if execution.phase.to_sym == :recovery_provider_completed
75
76
  invocation.output, invocation.usage = material.output, material.usage
@@ -77,36 +78,25 @@ module Phronomy
77
78
  prepare_saved_provider_calls(execution, invocation, material.assistant_message) if action == :framework_calls
78
79
  end
79
80
 
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") ||
81
+ error = if action == :failed_terminal
82
+ failure = execution.metadata.dig(ExecutionMetadata::RECOVERY_METADATA_KEY, "failure") ||
84
83
  {"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)
84
+ RecoverySupport.error_from_failure(failure)
105
85
  end
86
+ main.deliver_on_event_loop(ExecutionCoordinator::ContinueRecoveredCommand.new(
87
+ coordinator: main,
88
+ execution_id: execution.execution_id,
89
+ expected_execution_revision: execution.execution_revision,
90
+ continuation: action,
91
+ invocation: invocation,
92
+ runtime_projection: projection,
93
+ result_task: completion,
94
+ error: error
95
+ ))
106
96
  end
107
97
 
108
98
  def prepare_saved_provider_calls(execution, invocation, message)
109
- record = RecoverySupport.latest_assistant_record(execution)
99
+ record = SavedContextReader.latest_assistant_record(execution)
110
100
  calls = message.tool_calls.respond_to?(:values) ? message.tool_calls.values : Array(message.tool_calls)
111
101
  framework_calls = calls.select { |call| agent.__framework_call?(call.name) }
112
102
  if framework_calls.empty?
@@ -119,23 +109,10 @@ module Phronomy
119
109
  Phronomy::Agent::AgentInvocation.new(agent: agent, input: nil,
120
110
  config: {execution_id: execution.execution_id, phronomy_execution_coordinator: main},
121
111
  event_listener: agent.send(:_phronomy_event_listener),
122
- mode: (execution.metadata[RecoverySupport::INVOCATION_MODE_KEY] || "invoke").to_sym,
112
+ mode: (execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] || "invoke").to_sym,
123
113
  execution_id: execution.execution_id)
124
114
  end
125
115
 
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
116
  def deliver_resolution_required(execution, descriptor)
140
117
  unless descriptor
141
118
  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
 
@@ -70,7 +70,7 @@ module Phronomy
70
70
 
71
71
  def classify(execution)
72
72
  if framework_batch?(execution)
73
- return Phronomy::Recovery::Classification.new(disposition: Phronomy::Recovery::RESUMABLE, reason: :framework_tools)
73
+ return Phronomy::Agent::RecoveryRules::Classification.new(disposition: Phronomy::Agent::RecoveryRules::RESUMABLE, reason: :framework_tools)
74
74
  end
75
75
  if execution.status == :preparing &&
76
76
  execution.phase.to_sym == :preparing
@@ -79,16 +79,16 @@ module Phronomy
79
79
  "execution #{execution.execution_id} is :preparing but replay safety " \
80
80
  "was not durably established"
81
81
  end
82
- return Phronomy::Recovery::Classification.new(
83
- disposition: Phronomy::Recovery::RESUMABLE,
82
+ return Phronomy::Agent::RecoveryRules::Classification.new(
83
+ disposition: Phronomy::Agent::RecoveryRules::RESUMABLE,
84
84
  reason: :initial_preparation
85
85
  )
86
86
  end
87
87
 
88
88
  if execution.status == :suspended &&
89
89
  execution.phase.to_sym == :approval
90
- return Phronomy::Recovery::Classification.new(
91
- disposition: Phronomy::Recovery::RESUMABLE,
90
+ return Phronomy::Agent::RecoveryRules::Classification.new(
91
+ disposition: Phronomy::Agent::RecoveryRules::RESUMABLE,
92
92
  reason: :approval_wait,
93
93
  facts: {
94
94
  approval_request_id:
@@ -105,8 +105,8 @@ module Phronomy
105
105
  when :recovery_provider_completed,
106
106
  :recovery_tools_completed,
107
107
  :recovery_resolved_failed
108
- return Phronomy::Recovery::Classification.new(
109
- disposition: Phronomy::Recovery::RESUMABLE,
108
+ return Phronomy::Agent::RecoveryRules::Classification.new(
109
+ disposition: Phronomy::Agent::RecoveryRules::RESUMABLE,
110
110
  reason: execution.phase
111
111
  )
112
112
  when :resuming
@@ -116,8 +116,8 @@ module Phronomy
116
116
  execution.approval_request[:approved]
117
117
  )
118
118
  unless approved
119
- return Phronomy::Recovery::Classification.new(
120
- disposition: Phronomy::Recovery::RESUMABLE,
119
+ return Phronomy::Agent::RecoveryRules::Classification.new(
120
+ disposition: Phronomy::Agent::RecoveryRules::RESUMABLE,
121
121
  reason: :approval_rejection_committed
122
122
  )
123
123
  end
@@ -127,8 +127,8 @@ module Phronomy
127
127
  execution
128
128
  )
129
129
  if descriptor
130
- return Phronomy::Recovery::Classification.new(
131
- disposition: Phronomy::Recovery::RESOLUTION_REQUIRED,
130
+ return Phronomy::Agent::RecoveryRules::Classification.new(
131
+ disposition: Phronomy::Agent::RecoveryRules::RESOLUTION_REQUIRED,
132
132
  reason: descriptor.fetch(:reason),
133
133
  subject: descriptor.fetch(:subject),
134
134
  allowed_outcomes:
@@ -143,20 +143,20 @@ module Phronomy
143
143
  end
144
144
 
145
145
  def install_on_event_loop(command)
146
- event_loop = @runtime.event_loop
146
+ environment = @environment
147
147
  plan = command.plan
148
148
  execution = plan.execution
149
- main = agent.send(:execution_coordinator_for, agent.__coordination_config)
149
+ main = agent.send(:execution_coordinator_for, agent.__execution_wiring)
150
150
  admitted = false
151
151
  bound = false
152
152
  installed = false
153
153
 
154
- event_loop.admit_agent_execution(
154
+ environment.registry.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
+ environment.registry.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
- assistant_message: plan.material.assistant_message
170
+ assistant_message: plan.material.assistant_message, cancellation_requested: plan.material.cancellation_requested
171
171
  )
172
172
  end
173
173
 
174
- event_loop.install_agent_execution(
174
+ environment.registry.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
+ environment.registry.mark_agent_execution_admission(
188
188
  agent.agent_id,
189
189
  execution_id: execution.execution_id,
190
190
  state: :suspended
@@ -214,8 +214,8 @@ module Phronomy
214
214
  end
215
215
 
216
216
  case plan.classification.disposition
217
- when Phronomy::Recovery::RESOLUTION_REQUIRED
218
- event_loop.mark_agent_execution_admission(
217
+ when Phronomy::Agent::RecoveryRules::RESOLUTION_REQUIRED
218
+ environment.registry.mark_agent_execution_admission(
219
219
  agent.agent_id,
220
220
  execution_id: execution.execution_id,
221
221
  state: :recovery_required
@@ -247,7 +247,7 @@ module Phronomy
247
247
  )
248
248
  end
249
249
  command.completion.complete(agent)
250
- when Phronomy::Recovery::RESUMABLE
250
+ when Phronomy::Agent::RecoveryRules::RESUMABLE
251
251
  continue_resumable_on_event_loop(
252
252
  execution,
253
253
  completion: command.completion, material: plan.material
@@ -260,7 +260,7 @@ module Phronomy
260
260
  # simplecov:disable
261
261
  if installed
262
262
  begin
263
- event_loop.release_agent_execution(
263
+ environment.registry.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
+ environment.registry.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
+ environment.registry.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
  )
@@ -311,8 +311,8 @@ module Phronomy
311
311
  completion:, material:
312
312
  )
313
313
  # simplecov:disable
314
- event_loop = @runtime.event_loop
315
- main = agent.send(:execution_coordinator_for, agent.__coordination_config)
314
+ environment = @environment
315
+ main = agent.send(:execution_coordinator_for, agent.__execution_wiring)
316
316
 
317
317
  if framework_batch?(execution)
318
318
  internal = Phronomy::TaskResult.deferred(name: "framework-tool-recovery:#{execution.execution_id}")
@@ -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 = environment.registry.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}")