phronomy 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +52 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +28 -7
  6. data/benchmark/bench_agent_invoke.rb +25 -50
  7. data/benchmark/bench_context_assembler.rb +14 -11
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/benchmark/bench_tool_schema.rb +1 -1
  10. data/docs/application-recipes.md +229 -0
  11. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  12. data/docs/architecture/agent-transition-ownership.md +13 -89
  13. data/docs/architecture/backend-groups.md +152 -0
  14. data/docs/architecture/before-llm-input.md +3 -3
  15. data/docs/architecture/context-management.md +1 -1
  16. data/docs/architecture/dx05-agent-scope.md +119 -0
  17. data/docs/architecture/dx05-workflow-task-state.md +134 -0
  18. data/docs/architecture/error-api-review.md +245 -0
  19. data/docs/architecture/execution-abstraction-review.md +88 -0
  20. data/docs/architecture/execution-boundaries.md +28 -0
  21. data/docs/architecture/execution-metadata-and-values.md +6 -0
  22. data/docs/architecture/multi-agent-handoff.md +6 -5
  23. data/docs/architecture/persistence.md +27 -9
  24. data/docs/architecture/r8-unit1.md +104 -0
  25. data/docs/architecture/r8-unit10.md +72 -0
  26. data/docs/architecture/r8-unit11.md +71 -0
  27. data/docs/architecture/r8-unit12.md +67 -0
  28. data/docs/architecture/r8-unit13.md +61 -0
  29. data/docs/architecture/r8-unit14.md +72 -0
  30. data/docs/architecture/r8-unit15.md +65 -0
  31. data/docs/architecture/r8-unit16.md +54 -0
  32. data/docs/architecture/r8-unit17.md +73 -0
  33. data/docs/architecture/r8-unit18.md +92 -0
  34. data/docs/architecture/r8-unit19.md +61 -0
  35. data/docs/architecture/r8-unit2.md +55 -0
  36. data/docs/architecture/r8-unit20.md +51 -0
  37. data/docs/architecture/r8-unit21.md +79 -0
  38. data/docs/architecture/r8-unit22.md +74 -0
  39. data/docs/architecture/r8-unit23.md +81 -0
  40. data/docs/architecture/r8-unit3.md +130 -0
  41. data/docs/architecture/r8-unit4.md +79 -0
  42. data/docs/architecture/r8-unit5.md +115 -0
  43. data/docs/architecture/r8-unit6.md +71 -0
  44. data/docs/architecture/r8-unit7.md +70 -0
  45. data/docs/architecture/r8-unit8.md +78 -0
  46. data/docs/architecture/r8-unit9.md +73 -0
  47. data/docs/architecture/refactoring-closure.md +10 -1
  48. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  49. data/docs/architecture/storage-execution-boundaries.md +54 -0
  50. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  51. data/docs/architecture/tracing.md +1 -1
  52. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  53. data/docs/architecture.md +24 -11
  54. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  55. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  56. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  57. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  58. data/docs/decisions/032-storage-backend-composition.md +5 -0
  59. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  60. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  61. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  62. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  63. data/docs/decisions/040-configuration-default-composition.md +12 -1
  64. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  65. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  66. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  67. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  68. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  69. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  70. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  71. data/docs/decisions/062-content-store-service.md +52 -0
  72. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  73. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  74. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  75. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  76. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  77. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  78. data/docs/decisions/README.md +18 -1
  79. data/docs/execution-boundaries-preview.md +45 -0
  80. data/docs/failure-reason-codes.md +45 -0
  81. data/docs/features.md +12 -4
  82. data/docs/getting-started.md +52 -48
  83. data/docs/migrations/0.22.md +2 -2
  84. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  85. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  86. data/docs/migrations/persistence-failure-contracts.md +67 -0
  87. data/docs/migrations/r8-unit10.md +36 -0
  88. data/docs/migrations/r8-unit11.md +33 -0
  89. data/docs/migrations/r8-unit12.md +31 -0
  90. data/docs/migrations/r8-unit13.md +36 -0
  91. data/docs/migrations/r8-unit14.md +31 -0
  92. data/docs/migrations/r8-unit15.md +31 -0
  93. data/docs/migrations/r8-unit16.md +26 -0
  94. data/docs/migrations/r8-unit17.md +28 -0
  95. data/docs/migrations/r8-unit18.md +29 -0
  96. data/docs/migrations/r8-unit19.md +28 -0
  97. data/docs/migrations/r8-unit20.md +24 -0
  98. data/docs/migrations/r8-unit21.md +28 -0
  99. data/docs/migrations/r8-unit22.md +29 -0
  100. data/docs/migrations/r8-unit23.md +20 -0
  101. data/docs/migrations/r8-unit4.md +67 -0
  102. data/docs/migrations/r8-unit5.md +75 -0
  103. data/docs/migrations/r8-unit6.md +109 -0
  104. data/docs/migrations/r8-unit7.md +31 -0
  105. data/docs/migrations/r8-unit8.md +33 -0
  106. data/docs/migrations/r8-unit9.md +28 -0
  107. data/docs/migrations/storage-async-client.md +103 -0
  108. data/docs/migrations/vector-async-clients.md +110 -0
  109. data/docs/ordered-event-delivery.md +54 -0
  110. data/docs/persistence-backends.md +38 -21
  111. data/docs/runtime-and-concurrency.md +26 -1
  112. data/docs/workflow-completion.md +92 -0
  113. data/gemfiles/http_minimum.gemfile +5 -0
  114. data/lib/phronomy/agent/admission.rb +78 -0
  115. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  116. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  117. data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
  118. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  119. data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
  120. data/lib/phronomy/agent/api/agent.rb +13 -0
  121. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  122. data/lib/phronomy/agent/async_event_api.rb +132 -103
  123. data/lib/phronomy/agent/base.rb +146 -113
  124. data/lib/phronomy/agent/before_llm_input.rb +70 -0
  125. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  126. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  127. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  128. data/lib/phronomy/agent/control_request.rb +21 -0
  129. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  130. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  131. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  132. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  133. data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
  134. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  135. data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
  136. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  137. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
  138. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  139. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  140. data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
  141. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  142. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  143. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
  144. data/lib/phronomy/agent/execution_change.rb +161 -0
  145. data/lib/phronomy/agent/execution_environment.rb +36 -0
  146. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  147. data/lib/phronomy/agent/execution_observation.rb +35 -0
  148. data/lib/phronomy/agent/filterable.rb +188 -0
  149. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  150. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  151. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  152. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  153. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  154. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  155. data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
  156. data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
  157. data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
  158. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
  159. data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
  160. data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
  161. data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
  162. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  163. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  164. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  165. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  166. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  167. data/lib/phronomy/agent/persistence/records.rb +33 -0
  168. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  169. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  170. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  171. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  172. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
  173. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
  174. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
  175. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
  176. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  177. data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
  178. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  179. data/lib/phronomy/agent/retention.rb +17 -0
  180. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  181. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  182. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  183. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  184. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  185. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  186. data/lib/phronomy/agent/settings.rb +47 -0
  187. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  188. data/lib/phronomy/agent/store.rb +253 -0
  189. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
  190. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  191. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  192. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  193. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  194. data/lib/phronomy/common/error.rb +65 -1
  195. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  196. data/lib/phronomy/content_store/base.rb +7 -2
  197. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  198. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  199. data/lib/phronomy/context/assembly.rb +195 -0
  200. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  201. data/lib/phronomy/context/candidate.rb +51 -0
  202. data/lib/phronomy/context/constraint.rb +47 -0
  203. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  204. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  205. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  206. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  207. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  208. data/lib/phronomy/context/default_policy.rb +140 -0
  209. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  210. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  211. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  212. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  213. data/lib/phronomy/context/manifest_error.rb +10 -0
  214. data/lib/phronomy/context/prompt_template.rb +98 -0
  215. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  216. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  217. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  218. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  219. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  220. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  221. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  222. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  223. data/lib/phronomy/embeddings/authentication_error.rb +11 -0
  224. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
  225. data/lib/phronomy/embeddings/base.rb +43 -0
  226. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  227. data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
  228. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  229. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  230. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  231. data/lib/phronomy/engine/diagnostics.rb +1 -1
  232. data/lib/phronomy/engine/event_loop.rb +7 -7
  233. data/lib/phronomy/engine/execution_binding.rb +23 -0
  234. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  235. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  236. data/lib/phronomy/engine/fsm_session.rb +3 -3
  237. data/lib/phronomy/engine/metrics.rb +16 -14
  238. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  239. data/lib/phronomy/engine/runtime.rb +25 -12
  240. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  241. data/lib/phronomy/execution/async_operation.rb +41 -0
  242. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  243. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  244. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  245. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  246. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  247. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  248. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  249. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  250. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  251. data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
  252. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  253. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  254. data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
  255. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  256. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  257. data/lib/phronomy/execution/runnable.rb +24 -0
  258. data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
  259. data/lib/phronomy/execution/wait_policy.rb +24 -0
  260. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
  261. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  262. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  263. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  264. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  265. data/lib/phronomy/generation/low_confidence_error.rb +2 -2
  266. data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
  267. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  268. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  269. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  270. data/lib/phronomy/llm_adapter/base.rb +49 -68
  271. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  272. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  273. data/lib/phronomy/llm_adapter/message.rb +62 -0
  274. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  275. data/lib/phronomy/llm_adapter/request.rb +79 -0
  276. data/lib/phronomy/llm_adapter/response.rb +36 -0
  277. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  278. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  279. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  280. data/lib/phronomy/llm_adapter.rb +3 -16
  281. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  282. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  283. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  284. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  285. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  286. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  287. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  288. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  289. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  290. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  291. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  292. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  293. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  294. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  295. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +60 -44
  296. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  297. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  298. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  299. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  300. data/lib/phronomy/multi_agent/store.rb +156 -0
  301. data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
  302. data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
  303. data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
  304. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  305. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  306. data/lib/phronomy/persistence/content_repository.rb +26 -0
  307. data/lib/phronomy/persistence/errors.rb +16 -0
  308. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  309. data/lib/phronomy/persistence/persistence.rb +23 -0
  310. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  311. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  312. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  313. data/lib/phronomy/persistence/transaction.rb +86 -0
  314. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  315. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  316. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  317. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  318. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  319. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  320. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  321. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  322. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  323. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  324. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  325. data/lib/phronomy/storage/async/async_client.rb +60 -0
  326. data/lib/phronomy/storage/backend.rb +8 -2
  327. data/lib/phronomy/storage/condition_failed_error.rb +2 -2
  328. data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
  329. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  330. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  331. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  332. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  333. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  334. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  335. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  336. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  337. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  338. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  339. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  340. data/lib/phronomy/tool/authorization.rb +77 -0
  341. data/lib/phronomy/tool/base.rb +551 -9
  342. data/lib/phronomy/tool/call_request.rb +40 -0
  343. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  344. data/lib/phronomy/tool/operation.rb +88 -0
  345. data/lib/phronomy/tool/schema.rb +214 -0
  346. data/lib/phronomy/tool/settings.rb +31 -0
  347. data/lib/phronomy/tool/tool_error.rb +7 -0
  348. data/lib/phronomy/tool/tool_executor.rb +58 -0
  349. data/lib/phronomy/tools/agent.rb +22 -90
  350. data/lib/phronomy/tools/mcp.rb +21 -14
  351. data/lib/phronomy/tools/vector_search.rb +4 -4
  352. data/lib/phronomy/tracing/automatic.rb +11 -6
  353. data/lib/phronomy/tracing/base.rb +36 -7
  354. data/lib/phronomy/tracing/observation.rb +37 -0
  355. data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
  356. data/lib/phronomy/tracing/settings.rb +36 -0
  357. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  358. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  359. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  360. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  361. data/lib/phronomy/vector_store/base.rb +118 -49
  362. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  363. data/lib/phronomy/vector_store.rb +2 -17
  364. data/lib/phronomy/version.rb +1 -1
  365. data/lib/phronomy/workflow/completion.rb +11 -0
  366. data/lib/phronomy/workflow/execution/workflow.rb +37 -9
  367. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  368. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  369. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
  370. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
  371. data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
  372. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  373. data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
  374. data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
  375. data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
  376. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  377. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  378. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
  379. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
  380. data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
  381. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  382. data/lib/phronomy.rb +63 -16
  383. data/scripts/api_snapshot.rb +47 -15
  384. data/scripts/check_readme_ruby.rb +24 -29
  385. data/scripts/check_readme_runnable.rb +92 -81
  386. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  387. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  388. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  389. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  390. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  391. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  392. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  393. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  394. data/sig/phronomy/agent/admission.rbs +19 -0
  395. data/sig/phronomy/agent/agent_not_found_error.rbs +6 -0
  396. data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -0
  397. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  398. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  399. data/sig/phronomy/agent/store.rbs +73 -0
  400. data/sig/phronomy/agent/stream_callback_error.rbs +8 -0
  401. data/sig/phronomy/agent.rbs +29 -135
  402. data/sig/phronomy/common.rbs +7 -0
  403. data/sig/phronomy/content_store/contracts.rbs +13 -0
  404. data/sig/phronomy/context.rbs +152 -0
  405. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  406. data/sig/phronomy/embeddings/base.rbs +23 -0
  407. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  408. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  409. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  410. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  411. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  412. data/sig/phronomy/engine/observability.rbs +13 -0
  413. data/sig/phronomy/execution/async_operation.rbs +7 -0
  414. data/sig/phronomy/execution/blocking.rbs +5 -0
  415. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  416. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  417. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  418. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  419. data/sig/phronomy/execution/errors.rbs +7 -0
  420. data/sig/phronomy/execution/execution.rbs +41 -0
  421. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  422. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  423. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  424. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  425. data/sig/phronomy/execution/task_result.rbs +29 -0
  426. data/sig/phronomy/extensions.rbs +1 -21
  427. data/sig/phronomy/filter/filter_block_error.rbs +6 -0
  428. data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
  429. data/sig/phronomy/handoff.rbs +10 -4
  430. data/sig/phronomy/integrations.rbs +14 -0
  431. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  432. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  433. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  434. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  435. data/sig/phronomy/llm_context_window.rbs +10 -0
  436. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  437. data/sig/phronomy/multi_agent/store.rbs +54 -0
  438. data/sig/phronomy/multi_agent/team_busy_error.rbs +8 -0
  439. data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
  440. data/sig/phronomy/multi_agent.rbs +6 -3
  441. data/sig/phronomy/persistence/errors.rbs +18 -0
  442. data/sig/phronomy/persistence/migration.rbs +13 -0
  443. data/sig/phronomy/persistence/transaction.rbs +19 -0
  444. data/sig/phronomy/persistence.rbs +1 -99
  445. data/sig/phronomy/persistence_composition.rbs +19 -0
  446. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  447. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  448. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  449. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +4 -18
  450. data/sig/phronomy/tool.rbs +48 -4
  451. data/sig/phronomy/tracing/observation.rbs +7 -0
  452. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  453. data/sig/phronomy/vector_store/base.rbs +23 -0
  454. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +15 -0
  455. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  456. data/sig/phronomy/workflow/store.rbs +8 -0
  457. data/sig/phronomy/workflow.rbs +5 -1
  458. data/sig/phronomy.rbs +4 -49
  459. metadata +365 -117
  460. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  461. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  462. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  463. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  464. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  465. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  466. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  467. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  468. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  469. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  470. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  471. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  472. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  473. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  474. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  475. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  476. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  477. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  478. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  479. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  480. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  481. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  482. data/lib/phronomy/configuration/configuration.rb +0 -68
  483. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  484. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  485. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  486. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  487. data/lib/phronomy/engine/runnable.rb +0 -54
  488. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  489. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  490. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  491. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  492. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  493. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  494. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  495. data/lib/phronomy/recovery/recovery.rb +0 -186
  496. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  497. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  498. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  499. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  500. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  501. data/sig/phronomy/execution_receiver.rbs +0 -34
  502. data/sig/phronomy/llm_adapter.rbs +0 -11
  503. data/sig/phronomy/runtime.rbs +0 -76
  504. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  505. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  506. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  507. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  508. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  509. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  510. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  511. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  512. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  513. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  514. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  515. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  516. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  517. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -15,31 +15,22 @@ module Phronomy
15
15
  end
16
16
 
17
17
  def normalize_provider_outcome(value)
18
- return value if value.is_a?(Phronomy::Agent::ProviderCallOutcome)
18
+ return value if value.is_a?(Phronomy::LLMAdapter::Response)
19
19
 
20
20
  if value.is_a?(Hash)
21
- return Phronomy::Agent::ProviderCallOutcome.from_h(value)
21
+ return Phronomy::LLMAdapter::Response.from_h(value)
22
22
  end
23
23
 
24
- captured = Phronomy::Agent::ProviderCallOutcome.capture(value)
25
- return captured if captured
26
-
27
24
  raise ArgumentError,
28
- "LLM Recovery :succeeded requires a Provider result or ProviderCallOutcome-compatible Hash"
25
+ "LLM Recovery :succeeded requires an LLMAdapter::Response or its canonical Hash"
29
26
  end
30
27
 
31
28
  def resolution_failure(error)
32
- {
33
- "class" => error.class.name.to_s,
34
- "message" => error.message.to_s
35
- }.freeze
29
+ Phronomy::Error.diagnostic(error).freeze
36
30
  end
37
31
 
38
32
  def error_from_failure(failure)
39
- hash = failure.to_h { |key, value| [key.to_s, value] }
40
- Phronomy::Error.new(
41
- "#{hash.fetch("class", "Error")}: #{hash.fetch("message", "Recovery-resolved failure")}"
42
- )
33
+ Phronomy::Error.from_diagnostic(failure)
43
34
  end
44
35
 
45
36
  def event_payload(execution, descriptor)
@@ -47,7 +38,7 @@ module Phronomy
47
38
  execution_id: execution.execution_id,
48
39
  execution_revision: execution.execution_revision,
49
40
  reason: descriptor.fetch(:reason),
50
- subject: Phronomy::Recovery.normalize_subject(
41
+ subject: Phronomy::Agent::RecoveryRules.normalize_subject(
51
42
  descriptor.fetch(:subject)
52
43
  ),
53
44
  allowed_outcomes: Array(
@@ -69,7 +60,7 @@ module Phronomy
69
60
  type: :llm_call,
70
61
  llm_call_id: llm_call_id
71
62
  },
72
- allowed_outcomes: Phronomy::Recovery::OUTCOMES,
63
+ allowed_outcomes: Phronomy::Agent::RecoveryRules::OUTCOMES,
73
64
  facts: {
74
65
  manifest_ref: execution.metadata["manifest_ref"],
75
66
  call_sequence: execution.llm_calls.length + 1
@@ -103,7 +94,7 @@ module Phronomy
103
94
  allowed_outcomes: Array(
104
95
  recovery["allowed_outcomes"] ||
105
96
  recovery[:allowed_outcomes] ||
106
- Phronomy::Recovery::OUTCOMES
97
+ Phronomy::Agent::RecoveryRules::OUTCOMES
107
98
  ).map(&:to_sym),
108
99
  facts: {
109
100
  tool_call_id: hash["tool_call_id"],
@@ -145,7 +136,7 @@ module Phronomy
145
136
  type: :tool_invocation,
146
137
  tool_invocation_id: first.fetch("tool_invocation_id")
147
138
  },
148
- allowed_outcomes: Phronomy::Recovery::OUTCOMES,
139
+ allowed_outcomes: Phronomy::Agent::RecoveryRules::OUTCOMES,
149
140
  facts: {
150
141
  tool_call_id: first["tool_call_id"],
151
142
  tool_name: first["tool_name"],
@@ -194,7 +185,7 @@ module Phronomy
194
185
  end.freeze
195
186
  end
196
187
 
197
- def build_recovery_hash(subjects, reason: :outcome_unknown, allowed_outcomes: Phronomy::Recovery::OUTCOMES)
188
+ def build_recovery_hash(subjects, reason: :outcome_unknown, allowed_outcomes: Phronomy::Agent::RecoveryRules::OUTCOMES)
198
189
  {
199
190
  "version" => ExecutionMetadata::CONTRACT_VERSION,
200
191
  "reason" => reason.to_s,
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Exact identity reserved by a coordinating domain. Correlation is immutable;
6
+ # mutable routing fences belong to the coordinator, never to this identity.
7
+ # @api public
8
+ ReservedExecution = Data.define(:agent_id, :execution_id, :correlation) do
9
+ def initialize(agent_id:, execution_id:, correlation: nil)
10
+ raise ArgumentError, "reserved identities must not be empty" if agent_id.to_s.empty? || execution_id.to_s.empty?
11
+ super(agent_id: agent_id.to_s.freeze, execution_id: execution_id.to_s.freeze,
12
+ correlation: Phronomy::Values::Immutable.copy(correlation))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # A durable reference prevents whole-Agent purge. The referencing domain
6
+ # decides when its opaque owner key can be released.
7
+ # @api public
8
+ Retention = Data.define(:agent_id, :execution_id, :owner_key) do
9
+ def initialize(agent_id:, owner_key:, execution_id: nil)
10
+ raise ArgumentError, "retention identities must not be empty" if agent_id.to_s.empty? || owner_key.to_s.empty?
11
+ super(agent_id: agent_id.to_s.freeze, execution_id: execution_id&.to_s&.freeze, owner_key: owner_key.to_s.freeze)
12
+ end
13
+
14
+ def to_h = {"agent_id" => agent_id, "execution_id" => execution_id, "owner_key" => owner_key}.freeze
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Adapts the concrete Engine lifecycle and sessions to Agent's connection.
6
+ # Construction alone starts no Runtime resources and creates no registry.
7
+ # @api private
8
+ class EngineEnvironment < ExecutionEnvironment
9
+ def initialize(runtime: Phronomy::Runtime.instance)
10
+ @runtime = runtime
11
+ end
12
+
13
+ def registry = ExecutionRegistry.for(@runtime.event_loop)
14
+ def existing_registry = ExecutionRegistry.existing_for(@runtime)
15
+
16
+ def ownership
17
+ existing_ownership || @runtime.__register_shutdown_participant(
18
+ key: OwnershipRegistry, participant: OwnershipRegistry.new(environment: self)
19
+ )
20
+ end
21
+
22
+ def existing_ownership = @runtime.__shutdown_participant(key: OwnershipRegistry)
23
+ def executing? = @runtime.event_loop.current?
24
+ def session_phase(id) = @runtime.event_loop.fsm_session_state(id)
25
+
26
+ def submit(**options, &operation)
27
+ Phronomy::Execution.submit(runtime: @runtime, **options, &operation)
28
+ end
29
+
30
+ # Pool sizing is an execution resource choice, separate from Agent's
31
+ # authorization decision and timeout selection. Read at submission time.
32
+ def submit_authorization(timeout:, cancellation_token:, &operation)
33
+ submit(pool_name: :authorization,
34
+ size: Phronomy::RuntimeSettings.current.authorization_pool_size,
35
+ queue_size: Phronomy::RuntimeSettings.current.authorization_queue_size,
36
+ timeout: timeout, cancellation_token: cancellation_token,
37
+ on_full: :raise, &operation)
38
+ end
39
+
40
+ def build_llm_client(adapter:)
41
+ Phronomy::LLMAdapter::AsyncClient.new(adapter: adapter, submitter: self)
42
+ end
43
+
44
+ def build_agent_session(invocation:, resume_event: nil, resume_phase: nil)
45
+ EngineSessionBuilder.build(invocation: invocation, environment: self,
46
+ event_loop: @runtime.event_loop, resume_event: resume_event, resume_phase: resume_phase)
47
+ end
48
+
49
+ def build_tool_session(invocation:, parent_sink:, resume_event: nil, resume_phase: nil)
50
+ ToolSessionBuilder.build(invocation: invocation, environment: self,
51
+ event_loop: @runtime.event_loop, parent_event_sink: parent_sink,
52
+ resume_event: resume_event, resume_phase: resume_phase)
53
+ end
54
+
55
+ def register_session(session, completion:)
56
+ @runtime.event_loop.register(session, completion: completion)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Engine-only construction. State vocabulary, ordered guards and entry
6
+ # operations are supplied by the Agent framework, not defined here.
7
+ # @api private
8
+ class EngineSessionBuilder
9
+ def self.build(invocation:, environment:, event_loop:, resume_event: nil, resume_phase: nil)
10
+ event_sink = Phronomy::FSMSession::EventSink.new(event_loop: event_loop)
11
+ invocation.bind_event_sink!(event_sink)
12
+ actions = InvocationActions.build_entry_actions(invocation.agent,
13
+ environment, mode: invocation.mode, event_sink: event_sink)
14
+ phase_machine = PhaseMachineBuilder.new(entry_actions: actions).build
15
+
16
+ Phronomy::FSMSession.new(
17
+ context: invocation,
18
+ event_sink: event_sink,
19
+ entry_point: InvocationTransitions::ENTRY_POINT,
20
+ phase_machine_class: phase_machine,
21
+ entry_actions: {},
22
+ auto_state_set: InvocationTransitions::AUTO_STATE_SET,
23
+ declared_states: InvocationTransitions::DECLARED_STATES,
24
+ wait_state_names: InvocationTransitions::WAIT_STATES,
25
+ external_events: InvocationTransitions::EXTERNAL_EVENTS,
26
+ recursion_limit: InvocationTransitions.recursion_limit(invocation.agent.class.max_iterations),
27
+ event_loop: event_loop,
28
+ resume_event: resume_event,
29
+ resume_phase: resume_phase
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "state_machines"
4
+
5
+ module Phronomy
6
+ module Agent
7
+ class PhaseMachineBuilder
8
+ def initialize(entry_actions: {}, transitions: InvocationTransitions, operation_name: "Agent")
9
+ @entry_actions = entry_actions
10
+ @transitions = transitions
11
+ @operation_name = operation_name
12
+ end
13
+
14
+ def build
15
+ entry_actions = @entry_actions
16
+ callback_builder = method(:build_entry_callback)
17
+ transitions = @transitions
18
+ declared_states = transitions::DECLARED_STATES
19
+ entry_point = transitions::ENTRY_POINT
20
+
21
+ Class.new do
22
+ attr_accessor :context, :current_event
23
+
24
+ state_machine :phase, initial: entry_point do
25
+ declared_states.each { |state_name| state state_name }
26
+
27
+ transitions::EVENTS.each do |event_name, definitions|
28
+ event event_name do
29
+ definitions.each do |definition|
30
+ transition definition[:from] => definition[:to],
31
+ :if => ->(machine) {
32
+ transitions.allowed?(definition, machine.context)
33
+ }
34
+ end
35
+ end
36
+ end
37
+
38
+ entry_actions.each do |state_name, callables|
39
+ callables.each do |callable|
40
+ after_transition(
41
+ to: state_name,
42
+ do: callback_builder.call(callable, state_name)
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def build_entry_callback(callable, state_name)
53
+ ->(machine) {
54
+ result = callable.call(machine.context)
55
+ if result.is_a?(Phronomy::TaskResult)
56
+ raise Phronomy::InvalidAsyncEntryActionError,
57
+ "#{@operation_name} entry action for #{state_name.inspect} returned Phronomy::TaskResult"
58
+ end
59
+ machine.context = result if result.respond_to?(:set_graph_metadata)
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Binds Agent Tool child progress to a concrete FSM session. Session routing
6
+ # is fresh for each incarnation and never replaces a durable Tool identity.
7
+ # @api private
8
+ class ToolSessionBuilder
9
+ def self.build(invocation:, environment:, event_loop:, parent_event_sink:,
10
+ resume_event: nil, resume_phase: nil)
11
+ event_sink = Phronomy::FSMSession::EventSink.new(event_loop: event_loop)
12
+ actions = ToolInvocationActions.build_entry_actions(environment, event_sink, parent_event_sink)
13
+ phase_machine = PhaseMachineBuilder.new(entry_actions: actions,
14
+ transitions: ToolInvocationTransitions, operation_name: "Tool").build
15
+
16
+ Phronomy::FSMSession.new(
17
+ context: invocation,
18
+ event_sink: event_sink,
19
+ entry_point: ToolInvocationTransitions::ENTRY_POINT,
20
+ phase_machine_class: phase_machine,
21
+ entry_actions: {},
22
+ auto_state_set: ToolInvocationTransitions::AUTO_STATE_SET,
23
+ declared_states: ToolInvocationTransitions::DECLARED_STATES,
24
+ wait_state_names: ToolInvocationTransitions::WAIT_STATES,
25
+ external_events: ToolInvocationTransitions::EXTERNAL_EVENTS,
26
+ recursion_limit: ToolInvocationTransitions::RECURSION_LIMIT,
27
+ event_loop: event_loop,
28
+ resume_event: resume_event,
29
+ resume_phase: resume_phase
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Phronomy
4
4
  module Agent
5
- class RubyLLMMaterializer
5
+ class RuntimeInput
6
6
  RuntimeProjection = Data.define(
7
7
  :system, :messages, :tool_classes, :ask_message,
8
8
  :model_config, :manifest, :manifest_ref
@@ -63,7 +63,7 @@ module Phronomy
63
63
  private
64
64
 
65
65
  def segment_from_record(record, position: 0)
66
- LLMInputManifest::Segment.new(
66
+ Phronomy::Context::LLMInputManifest::Segment.new(
67
67
  position: position,
68
68
  category: record.kind,
69
69
  role: record.role,
@@ -88,7 +88,7 @@ module Phronomy
88
88
  end
89
89
 
90
90
  def verify_adapter!(manifest)
91
- actual = Phronomy.configuration.llm_adapter.class.name
91
+ actual = Phronomy::Agent::Settings.current.llm_adapter.class.name
92
92
  return if manifest.adapter_name.nil? || manifest.adapter_name == actual
93
93
 
94
94
  raise Phronomy::ConfigurationError,
@@ -97,19 +97,16 @@ module Phronomy
97
97
 
98
98
  def verify_tool_definitions!(manifest)
99
99
  unless manifest.tool_definitions_ref
100
- return ToolDefinitionSet.build(
101
- @agent,
102
- additional_tools: @additional_tools
103
- )
100
+ return @agent.send(:tool_definition_set, additional_tools: @additional_tools)
104
101
  end
105
102
 
106
103
  expected_definitions = fetch_json(manifest.tool_definitions_ref)
107
104
  additional = @additional_tools
108
105
  if additional.empty?
109
- additional = Array(@agent.__coordination_config[:phronomy_handoff_bindings]).map(&:tool_class)
106
+ additional = Array(@agent.__execution_wiring[:phronomy_control_bindings]).map(&:tool_class)
110
107
  end
111
108
 
112
- ToolDefinitionSet.build(@agent, additional_tools: additional)
109
+ @agent.send(:tool_definition_set, additional_tools: additional)
113
110
  .select_definitions(expected_definitions)
114
111
  end
115
112
 
@@ -130,7 +127,7 @@ module Phronomy
130
127
  when :tool_result
131
128
  raise ArgumentError, "raw Tool result is not an LLM message"
132
129
  else
133
- RubyLLM::Message.new(
130
+ Phronomy::LLMAdapter::Message.new(
134
131
  role: segment.role,
135
132
  content: @persistence.contents.fetch_text(segment.content_ref),
136
133
  tool_call_id: segment.tool_call_id
@@ -151,39 +148,25 @@ module Phronomy
151
148
  end
152
149
 
153
150
  tool_calls = materialize_tool_calls(payload["tool_calls"])
154
- RubyLLM::Message.new(
151
+ Phronomy::LLMAdapter::Message.new(
155
152
  role: role,
156
- content: initial_content_for(role, payload.fetch("content", nil), tool_calls),
157
- tool_calls: tool_calls.empty? ? nil : tool_calls,
153
+ content: payload.fetch("content", nil),
154
+ tool_calls: tool_calls,
158
155
  tool_call_id: payload["tool_call_id"],
159
- model: payload["model_id"]
156
+ metadata: {"model_id" => payload["model_id"]}.compact
160
157
  )
161
158
  end
162
159
 
163
- def initial_content_for(role, content, tool_calls)
164
- return "" if role == :assistant && content.nil? && !tool_calls.empty?
165
-
166
- (content.is_a?(Hash) || content.is_a?(Array)) ? JSON.generate(content) : content
167
- end
168
-
169
160
  def materialize_tool_calls(payloads)
170
- Array(payloads).each_with_object({}) do |payload, result|
171
- tool_call_id = payload.fetch("id").to_s
172
- if result.key?(tool_call_id)
173
- raise ArgumentError, "duplicate Tool Call in assistant message: #{tool_call_id}"
174
- end
175
- result[tool_call_id] = materialize_tool_call(payload)
161
+ Array(payloads).map do |payload|
162
+ # Read the pre-unit6 durable format explicitly; SDK objects are never
163
+ # reconstituted during recovery. New records use opaque metadata.
164
+ metadata = payload.fetch("metadata", {}).dup
165
+ metadata["thought_signature"] = payload["thought_signature"] if payload["thought_signature"]
166
+ Phronomy::Tool::CallRequest.new(id: payload.fetch("id"), name: payload.fetch("name"),
167
+ arguments: payload.fetch("arguments", {}), metadata: metadata)
176
168
  end
177
169
  end
178
-
179
- def materialize_tool_call(payload)
180
- RubyLLM::ToolCall.new(
181
- id: payload.fetch("id").to_s,
182
- name: payload.fetch("name"),
183
- arguments: payload.fetch("arguments", {}),
184
- thought_signature: payload["thought_signature"]
185
- )
186
- end
187
170
  end
188
171
  end
189
172
  end
@@ -9,13 +9,15 @@ module Phronomy
9
9
  module_function
10
10
 
11
11
  def manifest_from_ref(agent, ref)
12
- raw = agent.persistence.contents.fetch_json(ref)
13
- Phronomy::Agent::LLMInputManifest.from_h(raw)
12
+ Phronomy::Persistence::StorageBoundary.call do
13
+ raw = agent.persistence.contents.fetch_json(ref)
14
+ Phronomy::Context::LLMInputManifest.from_h(raw)
15
+ end
14
16
  end
15
17
 
16
18
  def materialize_projection(agent, manifest_ref)
17
19
  manifest = manifest_from_ref(agent, manifest_ref)
18
- projection = Phronomy::Agent::RubyLLMMaterializer.new(
20
+ projection = Phronomy::Agent::RuntimeInput.new(
19
21
  agent: agent,
20
22
  persistence: agent.persistence
21
23
  ).materialize(manifest: manifest, manifest_ref: manifest_ref)
@@ -40,7 +42,7 @@ module Phronomy
40
42
  else
41
43
  {}
42
44
  end
43
- usage = Phronomy::TokenUsage.new(
45
+ usage = Phronomy::LLMAdapter::TokenUsage.new(
44
46
  input: usage_hash["input"] || usage_hash[:input] || usage_hash["input_tokens"] || usage_hash[:input_tokens],
45
47
  output: usage_hash["output"] || usage_hash[:output] || usage_hash["output_tokens"] || usage_hash[:output_tokens],
46
48
  cached: usage_hash["cached"] || usage_hash[:cached] || usage_hash["cache_read_tokens"] || usage_hash[:cache_read_tokens] || usage_hash["cached_tokens"] || usage_hash[:cached_tokens],
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../common/configuration_error"
4
+
5
+ module Phronomy
6
+ module Agent
7
+ # Agent-owned option values and policy validation. Composition supplies
8
+ # concrete components and default values; execution reads at existing sites.
9
+ # @api private
10
+ class Settings
11
+ class << self
12
+ # Bind at boot without reading settings or starting runtime resources.
13
+ def install_provider(&provider)
14
+ raise ArgumentError, "settings provider requires a block" unless provider
15
+ @provider = provider
16
+ nil
17
+ end
18
+
19
+ # Read only when requested; no cache or change notification is involved.
20
+ def current
21
+ @provider.call
22
+ end
23
+ end
24
+
25
+ STREAM_CALLBACK_ERROR_POLICIES = %i[report fail_task].freeze
26
+ private_constant :STREAM_CALLBACK_ERROR_POLICIES
27
+
28
+ attr_accessor :default_model, :before_llm_input, :agent_store, :llm_adapter, :authorization_timeout
29
+ attr_reader :stream_callback_error_policy
30
+
31
+ def initialize(llm_adapter:, authorization_timeout:, stream_callback_error_policy:)
32
+ @llm_adapter = llm_adapter
33
+ @authorization_timeout = authorization_timeout
34
+ self.stream_callback_error_policy = stream_callback_error_policy
35
+ end
36
+
37
+ def stream_callback_error_policy=(value)
38
+ unless STREAM_CALLBACK_ERROR_POLICIES.include?(value)
39
+ allowed = STREAM_CALLBACK_ERROR_POLICIES.map(&:inspect).join(", ")
40
+ raise Phronomy::ConfigurationError,
41
+ "stream_callback_error_policy must be one of: #{allowed}"
42
+ end
43
+ @stream_callback_error_policy = value
44
+ end
45
+ end
46
+ end
47
+ end
@@ -14,7 +14,7 @@ module Phronomy
14
14
  @agent_id = agent_id
15
15
  end
16
16
 
17
- def create_root(definition:, context:, knowledge:, metadata:)
17
+ def create_root(definition:, context:, knowledge:, metadata:, retention: nil)
18
18
  root = Agent::AgentRoot.create(
19
19
  agent_id: agent_id,
20
20
  agent_definition_id: definition.fetch(:id),
@@ -23,6 +23,7 @@ module Phronomy
23
23
  )
24
24
  persistence.transaction do |tx|
25
25
  tx.agents.create(root)
26
+ tx.retentions.retain(retention) if retention
26
27
  records = initial_context_records(tx: tx, root: root, context: context)
27
28
  records.concat(initial_knowledge_records(tx: tx, root: root, knowledge: knowledge))
28
29
  unless records.empty?
@@ -137,8 +138,8 @@ module Phronomy
137
138
  build_knowledge_record(
138
139
  tx: tx,
139
140
  root: root,
140
- content: content,
141
- metadata: {}
141
+ content: content.is_a?(KnowledgeItem) ? content.content : content,
142
+ metadata: content.is_a?(KnowledgeItem) ? content.metadata : {}
142
143
  )
143
144
  end
144
145
  end