phronomy 0.27.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 (475) 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 +9 -3
  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/architecture/agent-chat-and-state-ownership.md +7 -1
  11. data/docs/architecture/agent-transition-ownership.md +13 -89
  12. data/docs/architecture/backend-groups.md +152 -0
  13. data/docs/architecture/before-llm-input.md +3 -3
  14. data/docs/architecture/context-management.md +1 -1
  15. data/docs/architecture/execution-abstraction-review.md +88 -0
  16. data/docs/architecture/execution-boundaries.md +28 -0
  17. data/docs/architecture/execution-metadata-and-values.md +6 -0
  18. data/docs/architecture/multi-agent-handoff.md +6 -5
  19. data/docs/architecture/persistence.md +27 -9
  20. data/docs/architecture/r8-unit1.md +104 -0
  21. data/docs/architecture/r8-unit10.md +72 -0
  22. data/docs/architecture/r8-unit11.md +71 -0
  23. data/docs/architecture/r8-unit12.md +67 -0
  24. data/docs/architecture/r8-unit13.md +61 -0
  25. data/docs/architecture/r8-unit14.md +72 -0
  26. data/docs/architecture/r8-unit15.md +65 -0
  27. data/docs/architecture/r8-unit16.md +54 -0
  28. data/docs/architecture/r8-unit17.md +73 -0
  29. data/docs/architecture/r8-unit18.md +92 -0
  30. data/docs/architecture/r8-unit19.md +61 -0
  31. data/docs/architecture/r8-unit2.md +55 -0
  32. data/docs/architecture/r8-unit20.md +51 -0
  33. data/docs/architecture/r8-unit21.md +79 -0
  34. data/docs/architecture/r8-unit22.md +74 -0
  35. data/docs/architecture/r8-unit23.md +81 -0
  36. data/docs/architecture/r8-unit3.md +130 -0
  37. data/docs/architecture/r8-unit4.md +79 -0
  38. data/docs/architecture/r8-unit5.md +115 -0
  39. data/docs/architecture/r8-unit6.md +71 -0
  40. data/docs/architecture/r8-unit7.md +70 -0
  41. data/docs/architecture/r8-unit8.md +78 -0
  42. data/docs/architecture/r8-unit9.md +73 -0
  43. data/docs/architecture/refactoring-closure.md +10 -1
  44. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  45. data/docs/architecture/storage-execution-boundaries.md +54 -0
  46. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  47. data/docs/architecture/tracing.md +1 -1
  48. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  49. data/docs/architecture.md +24 -11
  50. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  51. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  52. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  53. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  54. data/docs/decisions/032-storage-backend-composition.md +5 -0
  55. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  56. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  57. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  58. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  59. data/docs/decisions/040-configuration-default-composition.md +12 -1
  60. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  61. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  62. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  63. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  64. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  65. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  66. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  67. data/docs/decisions/062-content-store-service.md +52 -0
  68. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  69. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  70. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  71. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  72. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  73. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  74. data/docs/decisions/README.md +18 -1
  75. data/docs/execution-boundaries-preview.md +45 -0
  76. data/docs/features.md +8 -3
  77. data/docs/getting-started.md +9 -6
  78. data/docs/migrations/0.22.md +2 -2
  79. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  80. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  81. data/docs/migrations/persistence-failure-contracts.md +67 -0
  82. data/docs/migrations/r8-unit10.md +36 -0
  83. data/docs/migrations/r8-unit11.md +33 -0
  84. data/docs/migrations/r8-unit12.md +31 -0
  85. data/docs/migrations/r8-unit13.md +36 -0
  86. data/docs/migrations/r8-unit14.md +31 -0
  87. data/docs/migrations/r8-unit15.md +31 -0
  88. data/docs/migrations/r8-unit16.md +26 -0
  89. data/docs/migrations/r8-unit17.md +28 -0
  90. data/docs/migrations/r8-unit18.md +29 -0
  91. data/docs/migrations/r8-unit19.md +28 -0
  92. data/docs/migrations/r8-unit20.md +24 -0
  93. data/docs/migrations/r8-unit21.md +28 -0
  94. data/docs/migrations/r8-unit22.md +29 -0
  95. data/docs/migrations/r8-unit23.md +20 -0
  96. data/docs/migrations/r8-unit4.md +67 -0
  97. data/docs/migrations/r8-unit5.md +75 -0
  98. data/docs/migrations/r8-unit6.md +109 -0
  99. data/docs/migrations/r8-unit7.md +31 -0
  100. data/docs/migrations/r8-unit8.md +33 -0
  101. data/docs/migrations/r8-unit9.md +28 -0
  102. data/docs/migrations/storage-async-client.md +103 -0
  103. data/docs/migrations/vector-async-clients.md +110 -0
  104. data/docs/persistence-backends.md +38 -21
  105. data/docs/runtime-and-concurrency.md +26 -1
  106. data/lib/phronomy/agent/admission.rb +78 -0
  107. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  108. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  109. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  110. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  111. data/lib/phronomy/agent/async_event_api.rb +37 -32
  112. data/lib/phronomy/agent/base.rb +74 -72
  113. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  114. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  115. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  116. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  117. data/lib/phronomy/agent/control_request.rb +21 -0
  118. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  119. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  120. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  121. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  122. data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
  123. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  124. data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
  125. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  126. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
  127. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  128. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  129. data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
  130. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  131. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  132. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
  133. data/lib/phronomy/agent/execution_change.rb +161 -0
  134. data/lib/phronomy/agent/execution_environment.rb +36 -0
  135. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  136. data/lib/phronomy/agent/execution_observation.rb +35 -0
  137. data/lib/phronomy/agent/filterable.rb +182 -0
  138. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  139. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  140. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  141. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  142. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  143. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  144. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
  145. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  146. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  147. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  148. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  149. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  150. data/lib/phronomy/agent/persistence/records.rb +33 -0
  151. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  152. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  153. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  154. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  155. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
  156. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
  157. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
  158. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
  159. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  160. data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
  161. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  162. data/lib/phronomy/agent/retention.rb +17 -0
  163. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  164. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  165. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  166. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  167. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  168. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  169. data/lib/phronomy/agent/settings.rb +47 -0
  170. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  171. data/lib/phronomy/agent/store.rb +253 -0
  172. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
  173. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  174. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  175. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  176. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  177. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  178. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  179. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  180. data/lib/phronomy/context/assembly.rb +202 -0
  181. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  182. data/lib/phronomy/context/candidate.rb +51 -0
  183. data/lib/phronomy/context/constraint.rb +47 -0
  184. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  185. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  186. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  187. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  188. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  189. data/lib/phronomy/context/default_policy.rb +140 -0
  190. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  191. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  192. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  193. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  194. data/lib/phronomy/context/manifest_error.rb +10 -0
  195. data/lib/phronomy/context/prompt_template.rb +98 -0
  196. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  197. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  198. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  199. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  200. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  201. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  202. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  203. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  204. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  205. data/lib/phronomy/embeddings/base.rb +43 -0
  206. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  207. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  208. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  209. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  210. data/lib/phronomy/engine/diagnostics.rb +1 -1
  211. data/lib/phronomy/engine/event_loop.rb +7 -7
  212. data/lib/phronomy/engine/execution_binding.rb +23 -0
  213. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  214. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  215. data/lib/phronomy/engine/fsm_session.rb +3 -3
  216. data/lib/phronomy/engine/metrics.rb +16 -14
  217. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  218. data/lib/phronomy/engine/runtime.rb +25 -12
  219. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  220. data/lib/phronomy/execution/async_operation.rb +41 -0
  221. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  222. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  223. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  224. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  225. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  226. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  227. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  228. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  229. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  230. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  231. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  232. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  233. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  234. data/lib/phronomy/execution/runnable.rb +24 -0
  235. data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
  236. data/lib/phronomy/execution/wait_policy.rb +24 -0
  237. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
  238. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  239. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  240. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  241. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  242. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  243. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  244. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  245. data/lib/phronomy/llm_adapter/base.rb +49 -68
  246. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  247. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  248. data/lib/phronomy/llm_adapter/message.rb +62 -0
  249. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  250. data/lib/phronomy/llm_adapter/request.rb +79 -0
  251. data/lib/phronomy/llm_adapter/response.rb +36 -0
  252. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  253. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  254. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  255. data/lib/phronomy/llm_adapter.rb +3 -16
  256. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  257. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  258. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  259. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  260. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  261. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  262. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  263. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  264. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  265. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  266. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  267. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  268. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  269. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  270. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
  271. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  272. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  273. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  274. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  275. data/lib/phronomy/multi_agent/store.rb +156 -0
  276. data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
  277. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  278. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  279. data/lib/phronomy/persistence/content_repository.rb +26 -0
  280. data/lib/phronomy/persistence/errors.rb +16 -0
  281. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  282. data/lib/phronomy/persistence/persistence.rb +23 -0
  283. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  284. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  285. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  286. data/lib/phronomy/persistence/transaction.rb +86 -0
  287. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  288. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  289. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  290. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  291. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  292. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  293. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  294. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  295. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  296. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  297. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  298. data/lib/phronomy/storage/async/async_client.rb +60 -0
  299. data/lib/phronomy/storage/backend.rb +8 -2
  300. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  301. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  302. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  303. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  304. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  305. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  306. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  307. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  308. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  309. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  310. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  311. data/lib/phronomy/tool/authorization.rb +77 -0
  312. data/lib/phronomy/tool/base.rb +549 -9
  313. data/lib/phronomy/tool/call_request.rb +40 -0
  314. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  315. data/lib/phronomy/tool/operation.rb +88 -0
  316. data/lib/phronomy/tool/schema.rb +214 -0
  317. data/lib/phronomy/tool/settings.rb +31 -0
  318. data/lib/phronomy/tool/tool_error.rb +7 -0
  319. data/lib/phronomy/tool/tool_executor.rb +58 -0
  320. data/lib/phronomy/tools/agent.rb +22 -90
  321. data/lib/phronomy/tools/mcp.rb +21 -14
  322. data/lib/phronomy/tools/vector_search.rb +4 -4
  323. data/lib/phronomy/tracing/automatic.rb +11 -6
  324. data/lib/phronomy/tracing/base.rb +1 -1
  325. data/lib/phronomy/tracing/observation.rb +37 -0
  326. data/lib/phronomy/tracing/settings.rb +36 -0
  327. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  328. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  329. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  330. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  331. data/lib/phronomy/vector_store/base.rb +118 -49
  332. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  333. data/lib/phronomy/vector_store.rb +2 -17
  334. data/lib/phronomy/version.rb +1 -1
  335. data/lib/phronomy/workflow/completion.rb +11 -0
  336. data/lib/phronomy/workflow/execution/workflow.rb +7 -7
  337. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  338. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  339. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  340. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
  341. data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
  342. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  343. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  344. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  345. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  346. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  347. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  348. data/lib/phronomy.rb +57 -16
  349. data/scripts/api_snapshot.rb +35 -15
  350. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  351. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  352. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  353. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  354. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  355. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  356. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  357. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  358. data/sig/phronomy/agent/admission.rbs +19 -0
  359. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  360. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  361. data/sig/phronomy/agent/store.rbs +73 -0
  362. data/sig/phronomy/agent.rbs +14 -138
  363. data/sig/phronomy/common.rbs +7 -0
  364. data/sig/phronomy/content_store/contracts.rbs +13 -0
  365. data/sig/phronomy/context.rbs +152 -0
  366. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  367. data/sig/phronomy/embeddings/base.rbs +17 -0
  368. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  369. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  370. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  371. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  372. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  373. data/sig/phronomy/engine/observability.rbs +13 -0
  374. data/sig/phronomy/execution/async_operation.rbs +7 -0
  375. data/sig/phronomy/execution/blocking.rbs +5 -0
  376. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  377. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  378. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  379. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  380. data/sig/phronomy/execution/errors.rbs +7 -0
  381. data/sig/phronomy/execution/execution.rbs +41 -0
  382. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  383. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  384. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  385. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  386. data/sig/phronomy/execution/task_result.rbs +29 -0
  387. data/sig/phronomy/extensions.rbs +0 -21
  388. data/sig/phronomy/handoff.rbs +10 -4
  389. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  390. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  391. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  392. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  393. data/sig/phronomy/llm_context_window.rbs +10 -0
  394. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  395. data/sig/phronomy/multi_agent/store.rbs +54 -0
  396. data/sig/phronomy/multi_agent.rbs +6 -3
  397. data/sig/phronomy/persistence/errors.rbs +18 -0
  398. data/sig/phronomy/persistence/migration.rbs +13 -0
  399. data/sig/phronomy/persistence/transaction.rbs +19 -0
  400. data/sig/phronomy/persistence.rbs +1 -99
  401. data/sig/phronomy/persistence_composition.rbs +19 -0
  402. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  403. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  404. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  405. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
  406. data/sig/phronomy/tool.rbs +48 -4
  407. data/sig/phronomy/tracing/observation.rbs +7 -0
  408. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  409. data/sig/phronomy/vector_store/base.rbs +23 -0
  410. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  411. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  412. data/sig/phronomy/workflow/store.rbs +8 -0
  413. data/sig/phronomy/workflow.rbs +1 -1
  414. data/sig/phronomy.rbs +0 -49
  415. metadata +318 -117
  416. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  417. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  418. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  419. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  420. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  421. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  422. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  423. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  424. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  425. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  426. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  427. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  428. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  429. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  430. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  431. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  432. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  433. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  434. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  435. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  436. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  437. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  438. data/lib/phronomy/configuration/configuration.rb +0 -68
  439. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  440. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  441. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  442. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  443. data/lib/phronomy/engine/runnable.rb +0 -54
  444. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  445. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  446. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  447. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  448. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  449. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  450. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  451. data/lib/phronomy/recovery/recovery.rb +0 -186
  452. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  453. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  454. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  455. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  456. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  457. data/sig/phronomy/execution_receiver.rbs +0 -34
  458. data/sig/phronomy/llm_adapter.rbs +0 -11
  459. data/sig/phronomy/runtime.rbs +0 -76
  460. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  461. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  462. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  463. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  464. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  465. /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
  466. /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
  467. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  468. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  469. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  470. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  471. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  472. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  473. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  474. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  475. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../engine/concurrency/worker_input_restricted"
3
+ require_relative "../execution/concurrency/worker_input_restricted"
4
4
 
5
5
  require "securerandom"
6
- require_relative "concerns/filterable"
7
- require_relative "concerns/before_llm_input"
8
- require_relative "concerns/error_translation"
6
+ require_relative "filterable"
7
+ require_relative "before_llm_input"
9
8
 
10
9
  module Phronomy
11
10
  module Agent
@@ -36,9 +35,8 @@ module Phronomy
36
35
  include Phronomy::Concurrency::WorkerInputRestricted
37
36
 
38
37
  include Phronomy::Runnable
39
- include Concerns::Filterable
40
- include Concerns::BeforeLLMInput
41
- include Concerns::ErrorTranslation
38
+ include Filterable
39
+ include BeforeLLMInput
42
40
 
43
41
  APPROVAL_CONFIGURATION_INIT_MUTEX = Mutex.new
44
42
  private_constant :APPROVAL_CONFIGURATION_INIT_MUTEX
@@ -48,7 +46,7 @@ module Phronomy
48
46
  if name
49
47
  @model = name
50
48
  else
51
- @model || Phronomy.configuration.default_model
49
+ @model || Phronomy::Agent::Settings.current.default_model
52
50
  end
53
51
  end
54
52
 
@@ -129,18 +127,18 @@ module Phronomy
129
127
  end
130
128
  end
131
129
 
132
- # Binds one Application-constructed ContextPolicy instance to this
130
+ # Binds one Application-constructed Phronomy::Context::ContextPolicy instance to this
133
131
  # Agent class. Policy binding is Application code/runtime wiring rather
134
132
  # than durable Agent state.
135
133
  def context_policy(*args)
136
134
  if args.empty?
137
135
  return @context_policy if instance_variable_defined?(:@context_policy)
138
136
  return superclass.context_policy if superclass.respond_to?(:context_policy)
139
- return ContextPolicies::Default.instance
137
+ raise Phronomy::ConfigurationError, "Agent ContextPolicy has not been configured"
140
138
  end
141
- unless args.length == 1 && args.first.is_a?(ContextPolicy)
139
+ unless args.length == 1 && args.first.is_a?(Phronomy::Context::ContextPolicy)
142
140
  raise ArgumentError,
143
- "context_policy expects one Phronomy::Agent::ContextPolicy instance"
141
+ "context_policy expects one Phronomy::Context::ContextPolicy instance"
144
142
  end
145
143
 
146
144
  @context_policy = args.first
@@ -171,6 +169,7 @@ module Phronomy
171
169
  agent_id: SecureRandom.uuid,
172
170
  context: nil,
173
171
  knowledge: [],
172
+ retention: nil,
174
173
  persistence: nil,
175
174
  metadata: {},
176
175
  on_event: nil,
@@ -180,6 +179,7 @@ module Phronomy
180
179
  agent_id: agent_id,
181
180
  context: context,
182
181
  knowledge: knowledge,
182
+ retention: retention,
183
183
  persistence: persistence,
184
184
  metadata: metadata,
185
185
  on_event: on_event,
@@ -189,7 +189,7 @@ module Phronomy
189
189
 
190
190
  # Resolves one existing logical Agent. A live process-local owner wins
191
191
  # without a Persistence reload; otherwise the durable Agent is hydrated.
192
- def load(agent_id, persistence:, on_event: nil, &event_block)
192
+ def load(agent_id, persistence:, on_event: nil, execution_wiring: {}, &event_block)
193
193
  raise ArgumentError, "persistence is required" unless persistence
194
194
  if on_event && event_block
195
195
  raise ArgumentError, "Provide either on_event: or a block, not both"
@@ -199,10 +199,9 @@ module Phronomy
199
199
  raise ArgumentError, "agent_id must not be empty" if key.empty?
200
200
 
201
201
  listener_supplied = !on_event.nil? || !event_block.nil?
202
- runtime = Phronomy::Runtime.instance
203
202
  materialized = false
204
203
 
205
- agent = OwnershipRegistry.for(runtime).load(key, expected_class: self) do |owner_runtime|
204
+ agent = OwnershipRegistry.current.load(key, expected_class: self) do |owner_runtime|
206
205
  materialized = true
207
206
  instance = __construct_owned_agent(
208
207
  owner_runtime,
@@ -210,6 +209,7 @@ module Phronomy
210
209
  agent_id: key,
211
210
  persistence: persistence,
212
211
  load_existing: true,
212
+ execution_wiring: execution_wiring,
213
213
  on_event: on_event,
214
214
  &event_block
215
215
  )
@@ -236,14 +236,14 @@ module Phronomy
236
236
  key = agent_id.to_s
237
237
  raise ArgumentError, "agent_id must not be empty" if key.empty?
238
238
 
239
- OwnershipRegistry.existing_for(Phronomy::Runtime.instance)&.get(key, expected_class: self)
239
+ OwnershipRegistry.existing_current&.get(key, expected_class: self)
240
240
  end
241
241
 
242
242
  # Resolves the live Agent instance that currently owns execution_id in
243
243
  # this process. The Runtime returns only a read-only ownership view;
244
244
  # mutable Agent execution state remains EventLoop-owned.
245
245
  def live_for_execution(execution_id)
246
- owner = Phronomy::Agent::ExecutionRegistry.existing_for(Phronomy::Runtime.instance)&.agent_execution_owner(execution_id)
246
+ owner = Phronomy::Agent::ExecutionRegistry.existing_current&.agent_execution_owner(execution_id)
247
247
  unless owner
248
248
  raise Phronomy::ExecutionRehydrationRequiredError,
249
249
  "no live execution owner for #{execution_id}; durable rehydration is required"
@@ -268,9 +268,15 @@ module Phronomy
268
268
  end
269
269
  end
270
270
 
271
+ # Bound at Agent construction; no execution may silently switch Runtime.
271
272
  # @api private
272
- def __coordination_config
273
- @_phronomy_coordination_config || {}.freeze
273
+ def __execution_environment
274
+ @_phronomy_runtime_owner || ExecutionEnvironment.current
275
+ end
276
+
277
+ # @api private
278
+ def __execution_wiring
279
+ @_phronomy_execution_wiring || {}.freeze
274
280
  end
275
281
 
276
282
  # Framework-owned idempotent Tool operations opt into exact replay.
@@ -279,26 +285,29 @@ module Phronomy
279
285
 
280
286
  # @api private
281
287
  def __framework_call?(name)
282
- __framework_tool_replayable?(name) || Array(__coordination_config[:phronomy_handoff_bindings]).any? { |binding| binding.tool_name == name }
288
+ __framework_tool_replayable?(name) || Array(__execution_wiring[:phronomy_control_bindings]).any? { |binding| binding.tool_name == name }
283
289
  end
284
290
 
285
- # Captured Tool wiring is supplied explicitly; this hook only writes semantic values.
286
- # @api private
287
- def __prepare_coordination_record(execution, tx:) = execution
288
-
289
291
  # Runtime configuration only; no value returned here is serialized.
290
292
  # @api private
291
293
  def __invocation_config(config) = config
292
294
 
295
+ def knowledge_snapshot = persistence.knowledge_snapshot(agent_id: agent_id)
296
+
297
+ # Listener inheritance is an explicit orchestration choice, not a private getter.
298
+ def event_listener = _phronomy_event_listener
299
+
293
300
  attr_reader :agent_id, :persistence
294
301
 
295
302
  def initialize(
296
303
  agent_id: nil,
297
304
  context: nil,
298
305
  knowledge: [],
306
+ retention: nil,
299
307
  persistence: nil,
300
308
  metadata: {},
301
309
  load_existing: false,
310
+ execution_wiring: {},
302
311
  on_event: nil,
303
312
  &event_block
304
313
  )
@@ -306,6 +315,11 @@ module Phronomy
306
315
  raise ArgumentError, "Provide either on_event: or a block, not both"
307
316
  end
308
317
  @_phronomy_event_listener = on_event || event_block
318
+ @_phronomy_execution_wiring = execution_wiring.dup.freeze
319
+ @initial_retention = retention
320
+ if retention && retention.agent_id != agent_id.to_s
321
+ raise ArgumentError, "retention must refer to the new Agent"
322
+ end
309
323
 
310
324
  reserved_agent_id = @_phronomy_reserved_agent_id
311
325
  effective_agent_id = if agent_id.nil?
@@ -337,9 +351,8 @@ module Phronomy
337
351
  "load_existing: is an internal hydration option; use .load(agent_id, persistence:)"
338
352
  end
339
353
 
340
- runtime = Phronomy::Runtime.instance
341
354
  begin
342
- OwnershipRegistry.for(runtime).create(effective_agent_id, expected_class: self.class) do |owner_runtime|
355
+ OwnershipRegistry.current.create(effective_agent_id, expected_class: self.class) do |owner_runtime|
343
356
  __prepare_runtime_owner!(owner_runtime, effective_agent_id)
344
357
  initialize_owned_state(
345
358
  agent_id: effective_agent_id,
@@ -351,7 +364,7 @@ module Phronomy
351
364
  )
352
365
  self
353
366
  end
354
- rescue Phronomy::Storage::ConflictError => error
367
+ rescue Phronomy::Persistence::ConflictError => error
355
368
  raise Phronomy::AgentAlreadyExistsError,
356
369
  "Agent #{effective_agent_id.inspect} already exists durably: #{error.message}"
357
370
  end
@@ -427,7 +440,7 @@ module Phronomy
427
440
  runtime = @_phronomy_runtime_owner
428
441
  registry = OwnershipRegistry.for(runtime)
429
442
  token = registry.begin_purge(self)
430
- if Phronomy::Agent::ExecutionRegistry.existing_for(runtime)&.agent_execution_admitted?(agent_id)
443
+ if runtime.existing_registry&.agent_execution_admitted?(agent_id)
431
444
  registry.abort_purge(self, token)
432
445
  raise Phronomy::AgentBusyError,
433
446
  "Agent #{agent_id.inspect} has a nonterminal top-level execution"
@@ -436,20 +449,19 @@ module Phronomy
436
449
  begin
437
450
  persistence.transaction do |tx|
438
451
  tx.executions.assert_idle!(agent_id)
439
- if (routing = tx.handoff_states.load(agent_id))
440
- unless routing.phase == "stable" && tx.executions.list_active(routing.active_agent_id).empty?
441
- raise Phronomy::AgentBusyError, "Handoff anchor #{agent_id} owns an unfinished turn"
442
- end
443
- tx.handoff_states.delete(agent_id, expected_revision: routing.handoff_revision)
452
+ tx.guard_agent!(agent_id)
453
+ unless tx.retentions.list(agent_id).empty?
454
+ raise Phronomy::AgentBusyError, "Agent #{agent_id} is retained by durable coordination history"
444
455
  end
456
+ tx.cancellations.delete_for_agent(agent_id)
445
457
  tx.journals.delete(agent_id)
446
458
  tx.executions.delete_for_agent(agent_id)
447
459
  tx.agents.delete(agent_id)
448
460
  end
449
461
  rescue Phronomy::AgentBusyError,
450
- Phronomy::Storage::ConflictError,
451
- Phronomy::Storage::NotFoundError,
452
- Phronomy::Storage::SerializationError,
462
+ Phronomy::Persistence::ConflictError,
463
+ Phronomy::Persistence::NotFoundError,
464
+ Phronomy::Persistence::SerializationError,
453
465
  ArgumentError
454
466
  registry.abort_purge(self, token)
455
467
  raise
@@ -560,7 +572,7 @@ module Phronomy
560
572
  load_existing:
561
573
  )
562
574
  @persistence = persistence ||
563
- Phronomy.configuration.persistence ||
575
+ Phronomy::Agent::Settings.current.agent_store ||
564
576
  DefaultPersistence.build
565
577
  @agent_id = agent_id.to_s.freeze
566
578
 
@@ -607,7 +619,7 @@ module Phronomy
607
619
  def create_agent_root!(context:, knowledge:, metadata:)
608
620
  definition = self.class.agent_definition
609
621
  state_writer.create_root(
610
- definition: definition, context: context, knowledge: knowledge, metadata: metadata
622
+ definition: definition, context: context, knowledge: knowledge, metadata: metadata, retention: @initial_retention
611
623
  )
612
624
  end
613
625
 
@@ -708,7 +720,7 @@ module Phronomy
708
720
  end
709
721
 
710
722
  def _check_event_loop_reentrancy(sync_method, async_method)
711
- if Phronomy::Runtime.instance.event_loop.current?
723
+ if Phronomy::WaitPolicy.blocking_forbidden?
712
724
  raise Phronomy::EventLoopReentrancyError,
713
725
  "#{self.class.name}##{sync_method} cannot run on the EventLoop thread. " \
714
726
  "Use #{async_method} and return immediately."
@@ -723,12 +735,6 @@ module Phronomy
723
735
  task.fail(error)
724
736
  end
725
737
 
726
- def _translated_error(error)
727
- translate_and_reraise!(error)
728
- rescue => translated
729
- translated
730
- end
731
-
732
738
  def _deliver_stream_event(listener, event)
733
739
  return unless listener
734
740
 
@@ -772,7 +778,7 @@ module Phronomy
772
778
  end
773
779
 
774
780
  def _warn_stream_callback_error(message)
775
- logger = Phronomy.configuration.logger
781
+ logger = Phronomy::RuntimeSettings.current.logger
776
782
  unless logger
777
783
  _kernel_warn_safely(message)
778
784
  return
@@ -820,36 +826,28 @@ module Phronomy
820
826
  meta
821
827
  end
822
828
 
823
- def _apply_runtime_projection_to_chat(chat, projection, invocation: nil)
824
- if projection.system
825
- apply_instructions(
826
- chat,
827
- projection.system,
828
- cache: projection.model_config["cache_instructions"],
829
- provider: projection.model_config["provider"]
830
- )
831
- end
832
- projection.tool_classes.each do |tool_class|
833
- chat.with_tools(prepare_tool_class(tool_class, invocation: invocation))
829
+ def prepare_runtime_input(projection, invocation:)
830
+ tools = projection.tool_classes.map do |tool|
831
+ prepared = prepare_tool_class(tool, invocation: invocation)
832
+ prepared.is_a?(Class) ? prepared.new : prepared
834
833
  end
835
- projection.messages.each { |message| chat.messages << message }
836
- chat
834
+ invocation.tools = tools.to_h { |tool| [tool.name.to_sym, tool] }.freeze
835
+ invocation.messages = projection.messages.dup
836
+ invocation
837
837
  end
838
838
 
839
- def build_chat(model_config: nil)
840
- config = model_config || {
841
- "model" => self.class.model,
842
- "provider" => self.class.provider,
843
- "temperature" => self.class.temperature,
844
- "max_output_tokens" => self.class.max_output_tokens
845
- }
846
- RuntimeChatBuilder.build(config)
839
+ def build_llm_request(projection, invocation:)
840
+ definitions = Phronomy::Tool::DefinitionSet.build(tools: invocation.tools.values).definitions
841
+ Phronomy::LLMAdapter::Request.new(
842
+ model_config: projection.model_config, system: projection.system,
843
+ messages: invocation.messages, tools: definitions, message: projection.ask_message
844
+ )
847
845
  end
848
846
 
849
847
  def build_instructions(input)
850
848
  instr = self.class.instructions
851
849
  case instr
852
- when Phronomy::Agent::Context::Instruction::PromptTemplate
850
+ when Phronomy::Context::PromptTemplate
853
851
  vars = input.is_a?(Hash) ? input : {input: input}
854
852
  instr.format_system(**vars) || instr.format(**vars)
855
853
  when String then instr
@@ -858,10 +856,6 @@ module Phronomy
858
856
  end
859
857
  end
860
858
 
861
- def apply_instructions(chat, text, cache: false, provider: nil)
862
- RuntimeChatBuilder.apply_instructions(chat, text, cache: cache, provider: provider)
863
- end
864
-
865
859
  def extract_message(input)
866
860
  case input
867
861
  when String then input
@@ -884,6 +878,14 @@ module Phronomy
884
878
  raise Phronomy::CancellationError, message
885
879
  end
886
880
 
881
+ def tool_definition_set(additional_tools: [])
882
+ runtime_tools = (self.class.tools + Array(additional_tools)).freeze
883
+ Phronomy::Tool::DefinitionSet.build(
884
+ tools: runtime_tools.map { |tool| prepare_tool_class(tool) },
885
+ runtime_tools: runtime_tools
886
+ )
887
+ end
888
+
887
889
  def prepare_tool_class(tool_class, invocation: nil)
888
890
  return tool_class unless tool_class.is_a?(Class)
889
891
 
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ module BeforeLLMInput
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def before_llm_input(callable = nil, &block)
12
+ if callable.nil? && !block_given?
13
+ @before_llm_input
14
+ else
15
+ @before_llm_input = callable || block
16
+ end
17
+ end
18
+
19
+ def _before_llm_input = @before_llm_input
20
+ end
21
+
22
+ attr_accessor :before_llm_input
23
+
24
+ private
25
+
26
+ def run_before_llm_input_hooks(call_sequence:, config:)
27
+ hooks = [
28
+ Phronomy::Agent::Settings.current.before_llm_input,
29
+ self.class._before_llm_input,
30
+ @before_llm_input
31
+ ].compact
32
+ return Phronomy::Context::LLMInputPatch.empty if hooks.empty?
33
+
34
+ definition = self.class.agent_definition
35
+ context = Phronomy::Context::LLMInputBuildContext.new(
36
+ agent_id: agent_id,
37
+ agent_definition_id: definition.fetch(:id),
38
+ agent_definition_version: definition.fetch(:version),
39
+ config: config,
40
+ call_sequence: call_sequence
41
+ )
42
+ model_patch = {}
43
+ segments = []
44
+
45
+ hooks.each do |hook|
46
+ result = hook.call(context)
47
+ check_cancellation!(config, "invocation cancelled during before_llm_input hook")
48
+ next if result.nil?
49
+ unless result.is_a?(Phronomy::Context::LLMInputPatch)
50
+ raise TypeError,
51
+ "before_llm_input must return Phronomy::Context::LLMInputPatch or nil, got #{result.class}"
52
+ end
53
+ model_patch.merge!(result.model_config_patch) if result.model_config_patch
54
+ segments.concat(Array(result.segment_candidates))
55
+ end
56
+
57
+ Phronomy::Context::LLMInputPatch.new(
58
+ model_config_patch: model_patch.empty? ? nil : model_patch,
59
+ segment_candidates: segments.empty? ? nil : segments
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
@@ -18,7 +18,7 @@ module Phronomy
18
18
  raise ArgumentError, "Provide either on_event: or a block, not both"
19
19
  end
20
20
 
21
- persistence = Phronomy::Persistence.in_memory
21
+ persistence = Phronomy::PersistenceComposition.agent
22
22
  agent = definition.create(
23
23
  context: context,
24
24
  knowledge: knowledge,
@@ -43,7 +43,7 @@ module Phronomy
43
43
  "source_sequence" => record.sequence
44
44
  )
45
45
 
46
- Selection::Candidate.new(
46
+ Phronomy::Context::Candidate.new(
47
47
  candidate_id: "record:#{record.record_id}",
48
48
  source_kind: source_kind,
49
49
  category: record.kind,
@@ -55,7 +55,7 @@ module Phronomy
55
55
  llm_call_id: record.llm_call_id,
56
56
  tool_call_id: tool_call_id,
57
57
  sequence: sequence,
58
- constraint: Selection::Constraint.selectable(origin: :context_policy),
58
+ constraint: Phronomy::Context::Constraint.selectable(origin: :context_policy),
59
59
  priority: (source_kind == :working) ? 100 : 0,
60
60
  metadata: metadata
61
61
  )