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
@@ -9,8 +9,8 @@ module Phronomy
9
9
  private
10
10
 
11
11
  def begin_resolve_on_event_loop(request)
12
- event_loop = @runtime.event_loop
13
- state = event_loop.agent_execution_state(
12
+ environment = @environment
13
+ state = environment.registry.agent_execution_state(
14
14
  request.execution_id
15
15
  )
16
16
  unless state && state.agent.equal?(agent)
@@ -26,7 +26,7 @@ module Phronomy
26
26
  unless current.execution_revision ==
27
27
  request.expected_execution_revision
28
28
  request.completion.fail(
29
- Phronomy::Persistence::ConflictError.new(
29
+ Phronomy::Persistence::StateConflictError.new(
30
30
  "Recovery resolution revision conflict: expected " \
31
31
  "#{request.expected_execution_revision}, actual " \
32
32
  "#{current.execution_revision}"
@@ -38,7 +38,7 @@ module Phronomy
38
38
  descriptor =
39
39
  coordination_recovery_descriptor(current)
40
40
  unless descriptor &&
41
- Phronomy::Recovery.subject_equal?(
41
+ Phronomy::Agent::RecoveryRules.subject_equal?(
42
42
  descriptor.fetch(:subject),
43
43
  request.subject
44
44
  )
@@ -69,14 +69,12 @@ module Phronomy
69
69
  result: request.result,
70
70
  failure: request.failure
71
71
  )
72
- event_loop.mark_agent_execution_admission(
72
+ environment.registry.mark_agent_execution_admission(
73
73
  agent.agent_id,
74
74
  execution_id: current.execution_id,
75
75
  state: :recovery_required
76
76
  )
77
- task = @runtime.offload.submit(
78
- on_full: :raise
79
- ) do
77
+ task = @environment.submit(on_full: :raise) do
80
78
  prepare_resolution(operation)
81
79
  end
82
80
  task.on_complete do |result, error|
@@ -116,9 +114,9 @@ module Phronomy
116
114
  llm_call_id =
117
115
  operation.subject.fetch(:llm_call_id).to_s
118
116
  unless current.metadata[
119
- RecoverySupport::PENDING_LLM_ID_KEY
117
+ ExecutionMetadata::PENDING_LLM_ID_KEY
120
118
  ].to_s == llm_call_id
121
- raise Phronomy::Persistence::ConflictError,
119
+ raise Phronomy::Persistence::StateConflictError,
122
120
  "LLM Recovery subject is no longer pending"
123
121
  end
124
122
 
@@ -136,27 +134,27 @@ module Phronomy
136
134
  "automatic semantic redispatch is unavailable without a replay contract"
137
135
  }.freeze
138
136
  recovery = {
139
- "version" => RecoverySupport::CONTRACT_VERSION,
137
+ "version" => ExecutionMetadata::CONTRACT_VERSION,
140
138
  "resolution_outcome" => "not_performed",
141
139
  "failure" => failure
142
140
  }.freeze
143
141
  updated = current.with(
144
142
  phase: :recovery_resolved_failed,
145
143
  metadata: current.metadata.merge(
146
- RecoverySupport::RECOVERY_METADATA_KEY => recovery
144
+ ExecutionMetadata::RECOVERY_METADATA_KEY => recovery
147
145
  )
148
146
  )
149
147
  intended = ResolutionResult.new(execution: updated)
150
148
  save_resolution_result(current, intended)
151
149
  when :failed
152
150
  recovery = {
153
- "version" => RecoverySupport::CONTRACT_VERSION,
151
+ "version" => ExecutionMetadata::CONTRACT_VERSION,
154
152
  "failure" => operation.failure
155
153
  }
156
154
  updated = current.with(
157
155
  phase: :recovery_resolved_failed,
158
156
  metadata: current.metadata.merge(
159
- RecoverySupport::RECOVERY_METADATA_KEY =>
157
+ ExecutionMetadata::RECOVERY_METADATA_KEY =>
160
158
  recovery
161
159
  )
162
160
  )
@@ -165,12 +163,11 @@ module Phronomy
165
163
  when :succeeded
166
164
  # simplecov:disable
167
165
  outcome =
168
- Phronomy::Agent::ProviderCallOutcome.from_h(
166
+ Phronomy::LLMAdapter::Response.from_h(
169
167
  operation.result
170
168
  )
171
169
  updated = nil
172
170
  with_resolution_f1_capture do |tx|
173
- main = agent.send(:execution_coordinator_for, agent.__coordination_config)
174
171
  snapshot = {
175
172
  llm_results: [{
176
173
  llm_call_id: llm_call_id,
@@ -178,22 +175,22 @@ module Phronomy
178
175
  error: nil,
179
176
  streaming: (
180
177
  current.metadata[
181
- RecoverySupport::INVOCATION_MODE_KEY
178
+ ExecutionMetadata::INVOCATION_MODE_KEY
182
179
  ].to_s == "stream"
183
180
  ),
184
181
  manifest_ref: current.metadata.fetch(
185
182
  "manifest_ref"
186
183
  ),
187
184
  started_at: current.metadata[
188
- RecoverySupport::PENDING_LLM_STARTED_AT_KEY
185
+ ExecutionMetadata::PENDING_LLM_STARTED_AT_KEY
189
186
  ] || current.updated_at
190
187
  }.freeze].freeze,
191
188
  runtime_events: [].freeze,
192
189
  active_call: nil
193
190
  }.freeze
194
- records, calls = main.send(
195
- :encode_runtime_records,
191
+ records, calls = RuntimeRecordEncoder.encode(
196
192
  current,
193
+ agent_id: agent.agent_id,
197
194
  tx: tx,
198
195
  snapshot: snapshot,
199
196
  context_candidate: true,
@@ -210,15 +207,15 @@ module Phronomy
210
207
  :recovery_provider_completed : :recovery_tools
211
208
  metadata = current.metadata.dup
212
209
  metadata.delete(
213
- RecoverySupport::PENDING_LLM_ID_KEY
210
+ ExecutionMetadata::PENDING_LLM_ID_KEY
214
211
  )
215
212
  metadata.delete(
216
- RecoverySupport::PENDING_LLM_STARTED_AT_KEY
213
+ ExecutionMetadata::PENDING_LLM_STARTED_AT_KEY
217
214
  )
218
215
  metadata.delete("framework_calls_pending")
219
216
  metadata["framework_calls_pending"] = true unless framework_subjects.empty?
220
- if subjects.any? && Array(metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY]).empty?
221
- metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY] = subjects.map do |entry|
217
+ if subjects.any? && Array(metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY]).empty?
218
+ metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY] = subjects.map do |entry|
222
219
  {
223
220
  "tool_invocation_id" => entry.fetch("tool_invocation_id"),
224
221
  "llm_call_id" => entry.fetch("llm_call_id"),
@@ -231,11 +228,11 @@ module Phronomy
231
228
  end
232
229
  if external_subjects.empty?
233
230
  metadata.delete(
234
- RecoverySupport::RECOVERY_METADATA_KEY
231
+ ExecutionMetadata::RECOVERY_METADATA_KEY
235
232
  )
236
233
  else
237
234
  metadata[
238
- RecoverySupport::RECOVERY_METADATA_KEY
235
+ ExecutionMetadata::RECOVERY_METADATA_KEY
239
236
  ] = RecoverySupport.build_recovery_hash(
240
237
  external_subjects
241
238
  )
@@ -268,7 +265,7 @@ module Phronomy
268
265
  recovery = RecoverySupport.build_recovery_hash(subjects)
269
266
  end
270
267
  unless recovery
271
- raise Phronomy::Persistence::ConflictError,
268
+ raise Phronomy::Persistence::StateConflictError,
272
269
  "Tool Recovery state is missing"
273
270
  end
274
271
 
@@ -281,7 +278,7 @@ module Phronomy
281
278
  hash.fetch("state", "unresolved") == "unresolved"
282
279
  end
283
280
  unless subject_entry
284
- raise Phronomy::Persistence::ConflictError,
281
+ raise Phronomy::Persistence::StateConflictError,
285
282
  "Tool Recovery subject is no longer unresolved"
286
283
  end
287
284
  subject_entry =
@@ -309,7 +306,7 @@ module Phronomy
309
306
  updated = current.with(
310
307
  phase: :recovery_resolved_failed,
311
308
  metadata: current.metadata.merge(
312
- RecoverySupport::RECOVERY_METADATA_KEY =>
309
+ ExecutionMetadata::RECOVERY_METADATA_KEY =>
313
310
  resolved_recovery
314
311
  )
315
312
  )
@@ -329,7 +326,7 @@ module Phronomy
329
326
  updated = current.with(
330
327
  phase: :recovery_resolved_failed,
331
328
  metadata: current.metadata.merge(
332
- RecoverySupport::RECOVERY_METADATA_KEY =>
329
+ ExecutionMetadata::RECOVERY_METADATA_KEY =>
333
330
  recovery_with_failure
334
331
  )
335
332
  )
@@ -338,9 +335,7 @@ module Phronomy
338
335
  when :succeeded
339
336
  updated = nil
340
337
  with_resolution_f1_capture do |tx|
341
- main = agent.send(:execution_coordinator_for, agent.__coordination_config)
342
- result_ref = main.send(
343
- :put_runtime_content,
338
+ result_ref = RuntimeRecordEncoder.put_runtime_content(
344
339
  tx,
345
340
  operation.result
346
341
  )
@@ -363,9 +358,9 @@ module Phronomy
363
358
  subject_entry.fetch("llm_call_id").to_s
364
359
  }.freeze
365
360
  )
366
- records, _calls = main.send(
367
- :encode_runtime_records,
361
+ records, _calls = RuntimeRecordEncoder.encode(
368
362
  current,
363
+ agent_id: agent.agent_id,
369
364
  tx: tx,
370
365
  snapshot: {
371
366
  llm_results: [].freeze,
@@ -388,7 +383,7 @@ module Phronomy
388
383
  RecoverySupport.unresolved_subjects(
389
384
  next_recovery
390
385
  )
391
- tool_batch = Array(current.metadata[RecoverySupport::TOOL_BATCH_METADATA_KEY]).map do |entry|
386
+ tool_batch = Array(current.metadata[ExecutionMetadata::TOOL_BATCH_METADATA_KEY]).map do |entry|
392
387
  if entry.fetch("tool_invocation_id") == subject_entry.fetch("tool_invocation_id")
393
388
  entry.merge("status" => "completed", "result" => operation.result)
394
389
  else
@@ -402,8 +397,8 @@ module Phronomy
402
397
  working_records:
403
398
  current.working_records + records,
404
399
  metadata: current.metadata.merge(
405
- RecoverySupport::RECOVERY_METADATA_KEY => next_recovery,
406
- RecoverySupport::TOOL_BATCH_METADATA_KEY => tool_batch
400
+ ExecutionMetadata::RECOVERY_METADATA_KEY => next_recovery,
401
+ ExecutionMetadata::TOOL_BATCH_METADATA_KEY => tool_batch
407
402
  )
408
403
  )
409
404
  tx.executions.save(
@@ -477,27 +472,27 @@ module Phronomy
477
472
  if current.to_h == operation.execution.to_h
478
473
  raise(error.is_a?(ResolutionOutcomeUnknownError) ? error.original_error : error)
479
474
  end
480
- raise Phronomy::Persistence::ConflictError,
475
+ raise Phronomy::Persistence::StateConflictError,
481
476
  "Recovery resolution durable outcome conflicts with both expected pre-state and intended post-state"
482
477
  end
483
478
 
484
479
  def apply_resolve_on_event_loop(ready)
485
480
  request = ready.request
486
- event_loop = @runtime.event_loop
487
- state = event_loop.agent_execution_state(request.execution_id)
481
+ environment = @environment
482
+ state = environment.registry.agent_execution_state(request.execution_id)
488
483
  unless state && state.agent.equal?(agent)
489
484
  raise Phronomy::ExecutionRehydrationRequiredError,
490
485
  "recovered execution disappeared before resolution apply"
491
486
  end
492
487
  unless state.execution.equal?(ready.operation.execution) && state.fsm_session_id.nil?
493
- raise Phronomy::Persistence::ConflictError,
488
+ raise Phronomy::Persistence::StateConflictError,
494
489
  "Recovery execution changed before resolution apply"
495
490
  end
496
491
  raise ready.error if ready.error
497
492
 
498
493
  result = ready.result
499
494
  if result.execution
500
- event_loop.replace_agent_execution(request.execution_id, execution: result.execution)
495
+ environment.registry.replace_agent_execution(request.execution_id, execution: result.execution)
501
496
  end
502
497
  raise result.error if result.error
503
498
 
@@ -7,7 +7,7 @@ module Phronomy
7
7
  # Durable Agent Recovery owner/resolver.
8
8
  #
9
9
  # This class owns Agent-specific restart hydration and factual resolution.
10
- # Shared Recovery semantics remain in Phronomy::Recovery.
10
+ # Agent recovery semantics remain in RecoveryRules.
11
11
  # @api private
12
12
  class RecoveryCoordinator
13
13
  class ResolutionOutcomeUnknownError < Phronomy::Error
@@ -39,7 +39,7 @@ module Phronomy
39
39
  )
40
40
  ResolutionResult = Data.define(:execution)
41
41
  ResolutionPreparation = Data.define(:execution, :material, :error)
42
- RecoveryMaterial = Data.define(:projection, :messages, :assistant_message, :output, :usage)
42
+ RecoveryMaterial = Data.define(:projection, :messages, :assistant_message, :output, :usage, :cancellation_requested)
43
43
  RecoveryPlan = Data.define(
44
44
  :execution, :root, :manifest, :base_manifest,
45
45
  :projection, :classification, :material
@@ -49,7 +49,7 @@ module Phronomy
49
49
 
50
50
  def initialize(agent)
51
51
  @agent = agent
52
- @runtime = Phronomy::Runtime.instance
52
+ @environment = agent.__execution_environment
53
53
  end
54
54
 
55
55
  def recover_on_load!
@@ -57,26 +57,33 @@ module Phronomy
57
57
  Array(tx.executions.list_active(agent.agent_id))
58
58
  end
59
59
  if active.length > 1
60
- raise Phronomy::Persistence::ConflictError,
60
+ raise Phronomy::Persistence::StateConflictError,
61
61
  "multiple active AgentExecutions exist for #{agent.agent_id}"
62
62
  end
63
63
  return agent if active.empty?
64
64
 
65
65
  execution = active.first
66
66
  unless execution.agent_id.to_s == agent.agent_id.to_s
67
- raise Phronomy::Persistence::ConflictError,
67
+ raise Phronomy::Persistence::StateConflictError,
68
68
  "active AgentExecution belongs to another Agent: #{execution.agent_id}"
69
69
  end
70
70
 
71
- coordination = execution.metadata["coordination"]
72
- if coordination && agent.__coordination_config.empty?
71
+ coordination = execution.metadata["reservation"] || execution.metadata["execution_extension"]
72
+ if coordination && agent.__execution_wiring.empty?
73
73
  return agent
74
74
  end
75
75
 
76
+ if (raw = execution.metadata["execution_extension"])
77
+ extension = ExecutionExtensionState.from_h(raw)
78
+ binding = agent.__execution_wiring[:phronomy_execution_participant]&.binding
79
+ unless binding && binding.binding_key == extension.binding_key && binding.binding_version == extension.binding_version
80
+ raise Phronomy::ExecutionRehydrationRequiredError, "Execution #{execution.execution_id} needs its current participant binding"
81
+ end
82
+ end
76
83
  plan = prepare_plan(execution)
77
84
  classification = plan.classification
78
85
  if classification.disposition ==
79
- Phronomy::Recovery::RESOLUTION_REQUIRED &&
86
+ Phronomy::Agent::RecoveryRules::RESOLUTION_REQUIRED &&
80
87
  !agent.send(:_phronomy_event_listener)
81
88
  raise Phronomy::ConfigurationError,
82
89
  "Agent #{agent.agent_id.inspect} requires Recovery resolution; " \
@@ -114,21 +121,21 @@ module Phronomy
114
121
  expected_execution_revision:,
115
122
  subject:,
116
123
  outcome:,
117
- result: Phronomy::Recovery::MISSING,
118
- error: Phronomy::Recovery::MISSING
124
+ result: Phronomy::Agent::RecoveryRules::MISSING,
125
+ error: Phronomy::Agent::RecoveryRules::MISSING
119
126
  )
120
127
  agent.send(:__assert_live_agent!)
121
- normalized_outcome = Phronomy::Recovery.normalize_outcome(outcome)
122
- result_present = !result.equal?(Phronomy::Recovery::MISSING)
123
- error_present = !error.equal?(Phronomy::Recovery::MISSING)
124
- Phronomy::Recovery.validate_resolution_material!(
128
+ normalized_outcome = Phronomy::Agent::RecoveryRules.normalize_outcome(outcome)
129
+ result_present = !result.equal?(Phronomy::Agent::RecoveryRules::MISSING)
130
+ error_present = !error.equal?(Phronomy::Agent::RecoveryRules::MISSING)
131
+ Phronomy::Agent::RecoveryRules.validate_resolution_material!(
125
132
  outcome: normalized_outcome,
126
133
  result_present: result_present,
127
134
  error_present: error_present
128
135
  )
129
136
 
130
137
  normalized_subject =
131
- Phronomy::Recovery.normalize_subject(subject)
138
+ Phronomy::Agent::RecoveryRules.normalize_subject(subject)
132
139
  canonical_result = if result_present
133
140
  if normalized_subject[:type] == :llm_call &&
134
141
  normalized_outcome == :succeeded
@@ -187,14 +194,10 @@ module Phronomy
187
194
  private
188
195
 
189
196
  def post_control(command)
190
- @runtime.event_loop.post(
191
- Phronomy::Event.new(
192
- type: :agent_control,
193
- target_id:
194
- Phronomy::EventLoop::SYSTEM_CHANNEL_ID,
195
- payload: {command: command}.freeze
196
- )
197
- )
197
+ admission = command.is_a?(InstallCommand) || command.is_a?(ResolveCommand)
198
+ completion = admission ? command.completion : command.request.completion
199
+ @environment.registry.post(command,
200
+ admission: admission, completion: completion)
198
201
  rescue Phronomy::RuntimeShutdownError
199
202
  false
200
203
  end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Agent recovery subjects, factual resolutions and resumption classifications.
6
+ # Persistence evidence comparison belongs to Persistence::SnapshotComparison.
7
+ # @api private
8
+ module RecoveryRules
9
+ RESUMABLE = :resumable
10
+ RECONCILABLE = :reconcilable
11
+ RESOLUTION_REQUIRED = :resolution_required
12
+ DISPOSITIONS = [RESUMABLE, RECONCILABLE, RESOLUTION_REQUIRED].freeze
13
+
14
+ ALLOWED_OUTCOMES = %i[succeeded failed not_performed].freeze
15
+ # Internal shorthand used by the Agent Recovery implementation. This is not
16
+ # a public API constant; both names refer to the same frozen value.
17
+ OUTCOMES = ALLOWED_OUTCOMES
18
+
19
+ MISSING = Object.new.freeze
20
+
21
+ Classification = Data.define(
22
+ :disposition, :reason, :subject, :allowed_outcomes, :facts
23
+ ) do
24
+ def initialize(
25
+ disposition:,
26
+ reason:,
27
+ subject: nil,
28
+ allowed_outcomes: [],
29
+ facts: {}
30
+ )
31
+ normalized = disposition.to_sym
32
+ unless Phronomy::Agent::RecoveryRules::DISPOSITIONS.include?(normalized)
33
+ raise ArgumentError, "unknown Recovery disposition: #{disposition.inspect}"
34
+ end
35
+ super(
36
+ disposition: normalized,
37
+ reason: reason.to_sym,
38
+ subject: subject && Phronomy::Agent::RecoveryRules.normalize_subject(subject),
39
+ allowed_outcomes: Array(allowed_outcomes).map(&:to_sym).freeze,
40
+ facts: Phronomy::Values::Immutable.copy(facts || {})
41
+ )
42
+ end
43
+ end
44
+
45
+ module_function
46
+
47
+ def normalize_outcome(outcome)
48
+ normalized = outcome.to_sym
49
+ unless OUTCOMES.include?(normalized)
50
+ raise ArgumentError, "unsupported Recovery outcome: #{outcome.inspect}"
51
+ end
52
+ normalized
53
+ end
54
+
55
+ def validate_resolution_material!(outcome:, result_present:, error_present:)
56
+ normalized = normalize_outcome(outcome)
57
+ case normalized
58
+ when :succeeded
59
+ raise ArgumentError, "Recovery :succeeded requires result:" unless result_present
60
+ raise ArgumentError, "Recovery :succeeded forbids error:" if error_present
61
+ when :failed
62
+ raise ArgumentError, "Recovery :failed requires error:" unless error_present
63
+ raise ArgumentError, "Recovery :failed forbids result:" if result_present
64
+ when :not_performed
65
+ if result_present || error_present
66
+ raise ArgumentError, "Recovery :not_performed accepts neither result: nor error:"
67
+ end
68
+ end
69
+ true
70
+ end
71
+
72
+ def normalize_subject(subject)
73
+ hash = subject.to_h.transform_keys(&:to_sym)
74
+ type = hash.fetch(:type).to_sym
75
+ normalized = {type: type}
76
+ case type
77
+ when :llm_call
78
+ normalized[:llm_call_id] = required_id(hash, :llm_call_id)
79
+ when :tool_invocation
80
+ normalized[:tool_invocation_id] = required_id(hash, :tool_invocation_id)
81
+ when :persistence_operation
82
+ # Persistence operation references are structural only. Do not introduce
83
+ # a generic durable operation/recovery identity here.
84
+ normalized[:entity] = hash.fetch(:entity).to_sym
85
+ else
86
+ raise ArgumentError, "unsupported Recovery subject type: #{type.inspect}"
87
+ end
88
+ normalized.freeze
89
+ end
90
+
91
+ def subject_key(subject)
92
+ normalized = normalize_subject(subject)
93
+ case normalized.fetch(:type)
94
+ when :llm_call
95
+ "llm_call:#{normalized.fetch(:llm_call_id)}"
96
+ when :tool_invocation
97
+ "tool_invocation:#{normalized.fetch(:tool_invocation_id)}"
98
+ when :persistence_operation
99
+ "persistence_operation:#{normalized.fetch(:entity)}"
100
+ end
101
+ end
102
+
103
+ def subject_equal?(left, right)
104
+ normalize_subject(left) == normalize_subject(right)
105
+ rescue ArgumentError, KeyError
106
+ false
107
+ end
108
+
109
+ def required_id(hash, key)
110
+ value = hash.fetch(key)
111
+ text = value.to_s
112
+ raise ArgumentError, "#{key} must not be empty" if text.empty?
113
+
114
+ text.freeze
115
+ end
116
+ private_class_method :required_id
117
+ end
118
+ end
119
+ end