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
@@ -2,29 +2,13 @@
2
2
 
3
3
  module Phronomy
4
4
  module Agent
5
- class ContextAssembler
6
- ASSEMBLY_POLICY_VERSION = 9
5
+ class ContextPreparation
7
6
  SEGMENT_ORIGIN_METADATA_KEY = "phronomy_origin"
8
7
  POLICY_ORIGIN_METADATA_KEY = "context_policy_origin"
9
8
  POLICY_ITEM_ID_METADATA_KEY = "context_policy_item_id"
10
- SEMANTIC_CATEGORY_METADATA_KEY = "context_policy_semantic_category"
11
- CONTENT_FORMAT_METADATA_KEY = "context_policy_content_format"
12
- CONVERSATION_GROUP_ID_METADATA_KEY = "context_policy_conversation_group_id"
13
- TRUSTED_HANDOFF_METADATA_KEYS = %w[
14
- handoff_policy_category
15
- handoff_provenance
16
- ].freeze
17
- HANDOFF_POLICY_CATEGORY_METADATA_KEY = "handoff_policy_category"
18
9
  BEFORE_LLM_INPUT_ORIGIN = "before_llm_input"
19
10
  HANDOFF_CONTEXT_ORIGIN = "handoff_context"
20
11
 
21
- Prepared = Data.define(:input, :plan, :model_config, :call_sequence, :call_mode) do
22
- def initialize(**values)
23
- super
24
- freeze
25
- end
26
- end
27
-
28
12
  def initialize(
29
13
  agent:,
30
14
  persistence:,
@@ -38,26 +22,23 @@ module Phronomy
38
22
  @candidate_resolver = candidate_resolver || ContextCandidateResolver.new(
39
23
  content_loader: method(:fetch_content)
40
24
  )
41
- @input_builder = ContextPolicyInputBuilder.new(
25
+ @input_builder = Phronomy::Context::ContextPolicyInputBuilder.new(
42
26
  content_loader: method(:fetch_content)
43
27
  )
44
28
  end
45
29
 
46
30
  # Builds one immutable Policy input snapshot and executes Application Policy.
47
31
  # This method must run outside a Phronomy Persistence transaction.
48
- def prepare_initial(input:, agent_root:, execution:, config: {}, patch: LLMInputPatch.empty)
32
+ def prepare_initial(input:, agent_root:, execution:, config: {}, patch: Phronomy::Context::LLMInputPatch.empty)
49
33
  projection = journal_projection(agent_root)
50
34
  model_cfg = effective_model_config(config, patch)
51
- tool_set = ToolDefinitionSet.build(
52
- @agent,
53
- additional_tools: handoff_tool_classes(config)
54
- )
35
+ tool_set = @agent.send(:tool_definition_set, additional_tools: handoff_tool_classes(config))
55
36
  system_text = build_system_text(input)
56
37
  hook_candidates = normalize_candidates(patch.segment_candidates)
57
38
  input_ref = execution.metadata.fetch("current_input_ref")
58
39
  current_input_content = @persistence.contents.fetch_text(input_ref)
59
40
  excluded = [execution.metadata["current_input_record_id"]].compact
60
- handoff_context = config[:phronomy_handoff_context]
41
+ handoff_context = config[:phronomy_transfer_context]
61
42
 
62
43
  instructions = initial_instruction_items(
63
44
  system_text,
@@ -109,16 +90,13 @@ module Phronomy
109
90
  agent_root:,
110
91
  execution:,
111
92
  config: {},
112
- patch: LLMInputPatch.empty
93
+ patch: Phronomy::Context::LLMInputPatch.empty
113
94
  )
114
95
  projection = journal_projection(agent_root)
115
96
  model_cfg = effective_model_config(config, patch)
116
97
  hook_candidates = normalize_candidates(patch.segment_candidates)
117
- handoff_context = config[:phronomy_handoff_context]
118
- tool_set = ToolDefinitionSet.build(
119
- @agent,
120
- additional_tools: handoff_tool_classes(config)
121
- )
98
+ handoff_context = config[:phronomy_transfer_context]
99
+ tool_set = @agent.send(:tool_definition_set, additional_tools: handoff_tool_classes(config))
122
100
 
123
101
  instructions = retained_instruction_items(base_manifest)
124
102
 
@@ -153,68 +131,8 @@ module Phronomy
153
131
  end
154
132
 
155
133
  # Validates and canonicalizes a previously prepared Policy decision.
156
- # This method contains no ContextPolicy invocation and is safe to execute in
134
+ # This method contains no Phronomy::Context::ContextPolicy invocation and is safe to execute in
157
135
  # the short commit transaction after the caller revalidates durable revision.
158
- def finalize(prepared, persistence: @persistence)
159
- unless prepared.is_a?(Prepared)
160
- raise ArgumentError, "ContextAssembler#finalize expected ContextAssembler::Prepared"
161
- end
162
-
163
- plan = ContextPlanValidator.new.validate!(input: prepared.input, plan: prepared.plan)
164
- segments = []
165
- plan.instruction.each do |item|
166
- segments << segment_from_content_item(
167
- item,
168
- persistence: persistence,
169
- additional_metadata: {SEMANTIC_CATEGORY_METADATA_KEY => "instruction"}
170
- )
171
- end
172
- plan.knowledge.each do |item|
173
- segments << segment_from_content_item(
174
- item,
175
- persistence: persistence,
176
- additional_metadata: {SEMANTIC_CATEGORY_METADATA_KEY => "knowledge"}
177
- )
178
- end
179
- plan.conversation.each_with_index do |group, group_index|
180
- group_metadata = {
181
- SEMANTIC_CATEGORY_METADATA_KEY => "conversation",
182
- CONVERSATION_GROUP_ID_METADATA_KEY =>
183
- "conversation:#{prepared.call_sequence}:#{group_index}"
184
- }
185
- if tool_exchange_group?(group)
186
- group_metadata[HANDOFF_POLICY_CATEGORY_METADATA_KEY] = "tool_exchanges"
187
- end
188
-
189
- group.each do |item|
190
- segments << segment_from_content_item(
191
- item,
192
- persistence: persistence,
193
- additional_metadata: group_metadata
194
- )
195
- end
196
- end
197
-
198
- selected_tool_definitions = plan.tools.map(&:definition)
199
- ContextParts::Validators::FinalBudgetValidator.new(
200
- content_loader: lambda { |ref| fetch_content_from(persistence, ref) }
201
- ).validate!(
202
- token_budget: prepared.input.token_budget,
203
- segments: segments,
204
- extra_values: [selected_tool_definitions]
205
- )
206
-
207
- store_manifest(
208
- persistence: persistence,
209
- call_sequence: prepared.call_sequence,
210
- call_mode: prepared.call_mode,
211
- segments: segments,
212
- model_config_ref: persistence.contents.put_json(prepared.model_config),
213
- tool_definitions_ref: persistence.contents.put_json(selected_tool_definitions)
214
- )
215
- end
216
-
217
- private
218
136
 
219
137
  def initial_instruction_items(system_text, handoff_context, execution:)
220
138
  instructions = []
@@ -228,7 +146,7 @@ module Phronomy
228
146
  end
229
147
 
230
148
  def agent_instruction_item(system_text, execution:)
231
- ContextPolicyInput::InstructionItem.new(
149
+ Phronomy::Context::ContextPolicyInput::InstructionItem.new(
232
150
  id: "instruction:agent:#{execution.execution_id}:1",
233
151
  kind: :instruction,
234
152
  role: :system,
@@ -236,13 +154,13 @@ module Phronomy
236
154
  content_format: :text,
237
155
  estimated_tokens: estimate_value(system_text.to_s),
238
156
  required: true,
239
- provenance: ContextPolicyInput::Provenance.new(origin: :agent_configuration),
157
+ provenance: Phronomy::Context::ContextPolicyInput::Provenance.new(origin: :agent_configuration),
240
158
  metadata: {}
241
159
  )
242
160
  end
243
161
 
244
162
  def handoff_instruction_item(handoff_context, execution:)
245
- ContextPolicyInput::InstructionItem.new(
163
+ Phronomy::Context::ContextPolicyInput::InstructionItem.new(
246
164
  id: "instruction:handoff:#{execution.execution_id}:1",
247
165
  kind: :handoff_responsibility,
248
166
  role: :user,
@@ -250,7 +168,7 @@ module Phronomy
250
168
  content_format: :text,
251
169
  estimated_tokens: estimate_value(handoff_context.responsibility.to_s),
252
170
  required: true,
253
- provenance: ContextPolicyInput::Provenance.new(origin: :handoff_context),
171
+ provenance: Phronomy::Context::ContextPolicyInput::Provenance.new(origin: :handoff_context),
254
172
  metadata: {SEGMENT_ORIGIN_METADATA_KEY => HANDOFF_CONTEXT_ORIGIN}
255
173
  )
256
174
  end
@@ -294,7 +212,7 @@ module Phronomy
294
212
 
295
213
  def current_input_item(content, input_ref:, candidates:, agent_root:, execution:)
296
214
  next_sequence = Array(candidates).filter_map(&:sequence).max.to_i + 1
297
- ContextPolicyInput::ConversationItem.new(
215
+ Phronomy::Context::ContextPolicyInput::ConversationItem.new(
298
216
  id: "current-input:#{execution.execution_id}",
299
217
  kind: :current_input,
300
218
  role: :user,
@@ -303,7 +221,7 @@ module Phronomy
303
221
  sequence: next_sequence,
304
222
  estimated_tokens: estimate_value(content),
305
223
  required: true,
306
- provenance: ContextPolicyInput::Provenance.new(
224
+ provenance: Phronomy::Context::ContextPolicyInput::Provenance.new(
307
225
  origin: :working,
308
226
  content_ref: input_ref,
309
227
  record_id: execution.metadata["current_input_record_id"],
@@ -333,7 +251,7 @@ module Phronomy
333
251
  tools:,
334
252
  current_input:
335
253
  )
336
- token_budget = TokenBudgetResolver.new.resolve(model_config)
254
+ token_budget = Phronomy::Agent::Settings.current.llm_adapter.input_budget(model_config)
337
255
  policy_input = @input_builder.build(
338
256
  agent_id: agent_root.agent_id,
339
257
  execution_id: execution.execution_id,
@@ -353,36 +271,10 @@ module Phronomy
353
271
  "execution_revision" => execution.execution_revision
354
272
  }
355
273
  )
356
- plan = invoke_policy(policy_input)
357
- ContextPlanValidator.new.validate!(input: policy_input, plan: plan)
358
- Prepared.new(
359
- input: policy_input,
360
- plan: plan,
361
- model_config: model_config,
362
- call_sequence: call_sequence,
363
- call_mode: call_mode
364
- )
365
- end
366
-
367
- def invoke_policy(policy_input)
368
- tracer = Phronomy.configuration.tracer
369
- span = tracer.start_span(
370
- "context_policy",
371
- agent_id: policy_input.agent_id,
372
- execution_id: policy_input.execution_id,
373
- call_sequence: policy_input.call_sequence,
374
- policy_class: @policy.class.name || @policy.class.to_s,
375
- instruction_count: policy_input.instruction.length,
376
- knowledge_count: policy_input.knowledge.length,
377
- tool_count: policy_input.tools.length,
378
- conversation_group_count: policy_input.conversation.length
274
+ Phronomy::Context::Assembly.new.prepare(
275
+ input: policy_input, policy: @policy,
276
+ adapter_identity: Phronomy::Agent::Settings.current.llm_adapter.identity
379
277
  )
380
- result = @policy.call(policy_input)
381
- tracer.finish_span(span)
382
- result
383
- rescue => error
384
- tracer&.finish_span(span, error: error) if defined?(span) && span
385
- raise
386
278
  end
387
279
 
388
280
  def journal_projection(agent_root)
@@ -407,7 +299,7 @@ module Phronomy
407
299
  def instruction_item_from_manifest(segment)
408
300
  origin = segment.metadata[POLICY_ORIGIN_METADATA_KEY] ||
409
301
  ((segment.category.to_sym == :handoff_responsibility) ? "handoff_context" : "agent_configuration")
410
- ContextPolicyInput::InstructionItem.new(
302
+ Phronomy::Context::ContextPolicyInput::InstructionItem.new(
411
303
  id: segment.metadata[POLICY_ITEM_ID_METADATA_KEY] || "manifest-instruction:#{segment.position}",
412
304
  kind: segment.category,
413
305
  role: segment.role,
@@ -415,7 +307,7 @@ module Phronomy
415
307
  content_format: :text,
416
308
  estimated_tokens: estimate_value(fetch_content(segment.content_ref)),
417
309
  required: true,
418
- provenance: ContextPolicyInput::Provenance.new(
310
+ provenance: Phronomy::Context::ContextPolicyInput::Provenance.new(
419
311
  origin: origin.to_sym,
420
312
  content_ref: segment.content_ref
421
313
  ),
@@ -426,91 +318,17 @@ module Phronomy
426
318
  def tool_items(tool_set)
427
319
  tool_set.definitions.map do |definition|
428
320
  name = definition.fetch("name")
429
- ContextPolicyInput::ToolItem.new(
321
+ Phronomy::Context::ContextPolicyInput::ToolItem.new(
430
322
  id: "tool:#{name}",
431
323
  definition: definition,
432
324
  estimated_tokens: estimate_value(definition),
433
325
  required: false,
434
- provenance: ContextPolicyInput::Provenance.new(origin: :agent_configuration),
326
+ provenance: Phronomy::Context::ContextPolicyInput::Provenance.new(origin: :agent_configuration),
435
327
  metadata: {}
436
328
  )
437
329
  end.freeze
438
330
  end
439
331
 
440
- def store_manifest(
441
- persistence:,
442
- call_sequence:,
443
- call_mode:,
444
- segments:,
445
- model_config_ref:,
446
- tool_definitions_ref:
447
- )
448
- positioned = segments.each_with_index.map do |value, position|
449
- LLMInputManifest::Segment.new(**value.merge(position: position))
450
- end
451
- manifest = LLMInputManifest.new(
452
- call_sequence: call_sequence,
453
- call_mode: call_mode,
454
- segments: positioned,
455
- model_config_ref: model_config_ref,
456
- tool_definitions_ref: tool_definitions_ref,
457
- assembly_policy_version: ASSEMBLY_POLICY_VERSION,
458
- ruby_llm_version: defined?(RubyLLM::VERSION) ? RubyLLM::VERSION : nil,
459
- adapter_name: Phronomy.configuration.llm_adapter.class.name
460
- )
461
- [manifest, persistence.contents.put_json(manifest.to_h)]
462
- end
463
-
464
- def segment_from_content_item(item, persistence:, additional_metadata: {})
465
- content_ref = item.provenance.content_ref || store_item_content(item, persistence)
466
- metadata = sanitized_item_metadata(item).merge(additional_metadata).merge(
467
- CONTENT_FORMAT_METADATA_KEY => item.content_format.to_s,
468
- POLICY_ITEM_ID_METADATA_KEY => item.id,
469
- POLICY_ORIGIN_METADATA_KEY => item.provenance.origin.to_s,
470
- "journal_record_id" => item.provenance.record_id,
471
- "source_agent_id" => item.provenance.agent_id,
472
- "source_execution_id" => item.provenance.execution_id,
473
- "llm_call_id" => item.provenance.llm_call_id
474
- ).compact
475
-
476
- {
477
- category: item.kind,
478
- role: item.role,
479
- content_ref: content_ref,
480
- delivery: item.respond_to?(:delivery) ? item.delivery : :chat_message,
481
- tool_call_id: item.respond_to?(:tool_call_id) ? item.tool_call_id : nil,
482
- metadata: metadata
483
- }
484
- end
485
-
486
- def sanitized_item_metadata(item)
487
- raw = item.metadata.to_h.transform_keys(&:to_s)
488
- # :working origin is Phronomy-controlled (from InitialPreparation),
489
- # so handoff routing metadata on working records is equally trusted.
490
- trusted_handoff = if item.provenance.origin == :handoff || item.provenance.origin == :working
491
- raw.slice(*TRUSTED_HANDOFF_METADATA_KEYS)
492
- else
493
- {}
494
- end
495
-
496
- raw.except(*ContextPolicyInput::FRAMEWORK_METADATA_KEYS)
497
- .merge(trusted_handoff)
498
- end
499
-
500
- def tool_exchange_group?(group)
501
- Array(group).any? do |item|
502
- item.kind == :assistant_message && !item.tool_call_ids.empty?
503
- end && Array(group).any? { |item| item.kind == :tool_message }
504
- end
505
-
506
- def store_item_content(item, persistence)
507
- if item.content_format == :json
508
- persistence.contents.put_json(item.content)
509
- else
510
- persistence.contents.put_text(item.content.to_s)
511
- end
512
- end
513
-
514
332
  def effective_model_config(config, patch)
515
333
  apply_model_config_patch(model_config(config), patch.model_config_patch)
516
334
  end
@@ -530,7 +348,7 @@ module Phronomy
530
348
  values = patch.to_h.transform_keys(&:to_s)
531
349
  if values.key?("context_window")
532
350
  raise Phronomy::ConfigurationError,
533
- "context_window is model metadata; configure the RubyLLM model registry"
351
+ "context_window is model metadata; configure the LLM backend model metadata"
534
352
  end
535
353
  if values.key?("max_output_tokens") && !values["max_output_tokens"].nil?
536
354
  cap = Integer(values["max_output_tokens"])
@@ -549,7 +367,7 @@ module Phronomy
549
367
  metadata = (hash[:metadata] || hash["metadata"] || {})
550
368
  .to_h
551
369
  .transform_keys(&:to_s)
552
- validate_application_metadata!(metadata, source: "LLMInputPatch segment candidate")
370
+ validate_application_metadata!(metadata, source: "Phronomy::Context::LLMInputPatch segment candidate")
553
371
  {
554
372
  content: content,
555
373
  category: category,
@@ -560,7 +378,7 @@ module Phronomy
560
378
  end
561
379
 
562
380
  def validate_application_metadata!(metadata, source:)
563
- conflicts = metadata.keys.map(&:to_s) & ContextPolicyInput::FRAMEWORK_METADATA_KEYS
381
+ conflicts = metadata.keys.map(&:to_s) & Phronomy::Context::ContextPolicyInput::FRAMEWORK_METADATA_KEYS
564
382
  return if conflicts.empty?
565
383
 
566
384
  raise ArgumentError,
@@ -582,7 +400,7 @@ module Phronomy
582
400
  "source_kind" => "hook",
583
401
  "content_format" => content.is_a?(String) ? "text" : "json"
584
402
  )
585
- Selection::Candidate.new(
403
+ Phronomy::Context::Candidate.new(
586
404
  candidate_id: "hook:#{execution.execution_id}:#{call_sequence}:#{index}",
587
405
  source_kind: :hook,
588
406
  category: hook.fetch(:category),
@@ -594,7 +412,7 @@ module Phronomy
594
412
  llm_call_id: nil,
595
413
  tool_call_id: nil,
596
414
  sequence: next_sequence + index + 1,
597
- constraint: Selection::Constraint.selectable(origin: :context_policy),
415
+ constraint: Phronomy::Context::Constraint.selectable(origin: :context_policy),
598
416
  priority: 0,
599
417
  metadata: metadata
600
418
  )
@@ -607,8 +425,8 @@ module Phronomy
607
425
  def merge_handoff_candidates(candidates, handoff_context, execution:)
608
426
  return Array(candidates).freeze unless handoff_context
609
427
 
610
- unless handoff_context.is_a?(Phronomy::Agent::HandoffContext)
611
- raise ArgumentError, "phronomy_handoff_context must be a HandoffContext"
428
+ unless handoff_context.is_a?(Phronomy::Agent::TransferContext)
429
+ raise ArgumentError, "phronomy_transfer_context must be a TransferContext"
612
430
  end
613
431
 
614
432
  next_sequence = Array(candidates).filter_map(&:sequence).max.to_i
@@ -627,7 +445,7 @@ module Phronomy
627
445
  "handoff_provenance" => item.provenance.to_h
628
446
  )
629
447
 
630
- Selection::Candidate.new(
448
+ Phronomy::Context::Candidate.new(
631
449
  candidate_id: "handoff:#{execution.execution_id}:#{index}:#{item.provenance.origin_record_id || item.provenance.origin_tool_call_id || index}",
632
450
  source_kind: :handoff,
633
451
  category: item.candidate_category,
@@ -639,7 +457,7 @@ module Phronomy
639
457
  llm_call_id: item.provenance.origin_llm_call_id,
640
458
  tool_call_id: item.tool_call_id,
641
459
  sequence: next_sequence + index + 1,
642
- constraint: Selection::Constraint.selectable(origin: :handoff_context),
460
+ constraint: Phronomy::Context::Constraint.selectable(origin: :handoff_context),
643
461
  priority: 50,
644
462
  metadata: metadata
645
463
  )
@@ -655,7 +473,7 @@ module Phronomy
655
473
  end
656
474
 
657
475
  def handoff_tool_classes(config)
658
- Array(config[:phronomy_handoff_bindings]).map(&:tool_class).freeze
476
+ Array(config[:phronomy_control_bindings]).map(&:tool_class).freeze
659
477
  end
660
478
 
661
479
  def estimate_value(value)
@@ -664,13 +482,9 @@ module Phronomy
664
482
  end
665
483
 
666
484
  def fetch_content(ref)
667
- fetch_content_from(@persistence, ref)
668
- end
669
-
670
- def fetch_content_from(persistence, ref)
671
- persistence.contents.fetch_text(ref)
485
+ @persistence.contents.fetch_text(ref)
672
486
  rescue
673
- persistence.contents.fetch(ref)
487
+ @persistence.contents.fetch(ref)
674
488
  end
675
489
 
676
490
  def build_system_text(input)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Agent
5
+ # Value returned by a control capability after its domain policy is applied.
6
+ # Agent validates exclusivity and Source ownership before accepting it.
7
+ # @api public
8
+ ControlRequest = Data.define(:target_agent_id, :responsibility, :selection, :llm_call_id, :tool_call_id) do
9
+ def initialize(target_agent_id:, responsibility:, selection:, llm_call_id: nil, tool_call_id: nil)
10
+ raise ArgumentError, "target_agent_id is required" if target_agent_id.to_s.empty?
11
+ raise ArgumentError, "responsibility is required" if responsibility.to_s.strip.empty?
12
+ normalized = selection.to_h.transform_keys(&:to_sym)
13
+ unless normalized.values.all? { |value| value == true || value == false }
14
+ raise ArgumentError, "context selection values must be boolean"
15
+ end
16
+ super(target_agent_id: target_agent_id.to_s.freeze, responsibility: responsibility.to_s.strip.freeze,
17
+ selection: normalized.freeze, llm_call_id: llm_call_id&.to_s&.freeze, tool_call_id: tool_call_id&.to_s&.freeze)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,6 @@
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
6
  require "time"
@@ -1,6 +1,6 @@
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
6
  require "time"
@@ -33,7 +33,8 @@ module Phronomy
33
33
  end
34
34
 
35
35
  attr_accessor :input,
36
- :chat,
36
+ :messages,
37
+ :tools,
37
38
  :output,
38
39
  :usage,
39
40
  :input_blocked,
@@ -85,7 +86,8 @@ module Phronomy
85
86
  @event_sink = nil
86
87
  @mode = (mode || :invoke).to_sym
87
88
 
88
- @chat = nil
89
+ @messages = []
90
+ @tools = {}.freeze
89
91
  @output = nil
90
92
  @usage = nil
91
93
  @input_blocked = false
@@ -139,17 +141,6 @@ module Phronomy
139
141
  end
140
142
 
141
143
  durable_id = llm_call_id
142
- if durable_id.nil? &&
143
- Phronomy::Runtime.instance.event_loop.current?
144
- state =
145
- Phronomy::Agent::ExecutionRegistry.for(Phronomy::Runtime.instance.event_loop).agent_execution_state(
146
- execution_id
147
- )
148
- durable_id = state&.execution&.metadata&.fetch(
149
- ExecutionMetadata::PENDING_LLM_ID_KEY,
150
- nil
151
- )
152
- end
153
144
  unless durable_id
154
145
  raise Phronomy::ExecutionRehydrationRequiredError,
155
146
  "Provider Call semantic identity was not durably established before dispatch"
@@ -279,7 +270,7 @@ module Phronomy
279
270
 
280
271
  @user_message_sent = true
281
272
  @output = response.content
282
- @usage = Phronomy::TokenUsage.from_tokens(response.tokens)
273
+ @usage = response.usage
283
274
  @pending_tool_calls = []
284
275
  self
285
276
  end
@@ -321,7 +312,7 @@ module Phronomy
321
312
  def record_tool_results!
322
313
  @tool_invocations.each do |invocation|
323
314
  tool_content = invocation.result.to_s
324
- @chat.add_message(
315
+ @messages << Phronomy::LLMAdapter::Message.new(
325
316
  role: :tool,
326
317
  content: tool_content,
327
318
  tool_call_id: invocation.tool_call_id
@@ -430,7 +421,7 @@ module Phronomy
430
421
  private
431
422
 
432
423
  def handoff_matches_for(calls)
433
- bindings = Array(@config[:phronomy_handoff_bindings])
424
+ bindings = Array(@config[:phronomy_control_bindings])
434
425
  return [] if bindings.empty?
435
426
 
436
427
  by_name = bindings.to_h { |binding| [binding.tool_name.to_s, binding] }
@@ -441,25 +432,15 @@ module Phronomy
441
432
  end
442
433
 
443
434
  def build_handoff_request(tool_call, binding, llm_call_id:)
444
- handoff = binding.handoff
445
- unless handoff.source_agent.equal?(@agent)
446
- raise Phronomy::HandoffError,
447
- "Handoff capability is not bound to the active Source Agent"
435
+ unless binding.source_agent_id == @agent.agent_id
436
+ raise Phronomy::HandoffError, "Control capability is not bound to the active Source Agent"
448
437
  end
449
-
450
- args = tool_call.respond_to?(:arguments) ? tool_call.arguments : {}
451
- args = (args || {}).to_h.transform_keys(&:to_sym)
452
- selection = handoff.policy.selectable_categories.each_with_object({}) do |category, result|
453
- key = :"include_#{category}"
454
- result[category] = args[key] if args.key?(key)
438
+ request = binding.request(arguments: tool_call.arguments || {}, llm_call_id: llm_call_id,
439
+ tool_call_id: tool_call.respond_to?(:id) ? tool_call.id : nil)
440
+ unless request.is_a?(ControlRequest)
441
+ raise ArgumentError, "Control capability must return Agent::ControlRequest"
455
442
  end
456
- Phronomy::Agent::HandoffRequest.new(
457
- handoff: handoff,
458
- responsibility: args.fetch(:responsibility),
459
- selection_intent: selection,
460
- llm_call_id: llm_call_id,
461
- tool_call_id: tool_call.respond_to?(:id) ? tool_call.id : nil
462
- )
443
+ request
463
444
  end
464
445
 
465
446
  def apply_llm_event(event)
@@ -476,7 +457,7 @@ module Phronomy
476
457
  call = @current_llm_call
477
458
  @llm_results << {
478
459
  llm_call_id: call.fetch(:llm_call_id),
479
- response: canonical_response_for_llm_result(result),
460
+ response: result.response,
480
461
  error: result.error,
481
462
  streaming: result.streaming,
482
463
  manifest_ref: call.fetch(:manifest_ref),
@@ -490,16 +471,17 @@ module Phronomy
490
471
  end
491
472
 
492
473
  if result.error
493
- if result.error.is_a?(ToolCallIntercepted)
494
- accept_tool_calls!(
495
- result.error.tool_calls,
496
- llm_call_id: result.llm_call_id
497
- )
474
+ @error = result.error
475
+ elsif result.response.is_a?(Phronomy::LLMAdapter::Response)
476
+ @messages << result.response
477
+ if result.response.tool_call?
478
+ @usage = result.response.usage
479
+ accept_tool_calls!(result.response.tool_calls, llm_call_id: result.llm_call_id)
498
480
  else
499
- @error = result.error
481
+ apply_llm_response!(result.response)
500
482
  end
501
483
  else
502
- apply_llm_response!(result.response)
484
+ @error = Phronomy::LLMAdapter::InvalidResultError.new("LLM operation completed without a Response")
503
485
  end
504
486
  true
505
487
  end
@@ -510,7 +492,7 @@ module Phronomy
510
492
  end
511
493
 
512
494
  def warn_stale_llm_result(llm_call_id)
513
- Phronomy.configuration.logger&.warn(
495
+ Phronomy::RuntimeSettings.current.logger&.warn(
514
496
  "[Phronomy] Dropped stale Provider result: " \
515
497
  "execution_id=#{@execution_id} expected_llm_call_id=#{current_llm_call_id.inspect} " \
516
498
  "actual_llm_call_id=#{llm_call_id.inspect}"
@@ -519,14 +501,6 @@ module Phronomy
519
501
  nil
520
502
  end
521
503
 
522
- def canonical_response_for_llm_result(result)
523
- if result.error.is_a?(ToolCallIntercepted)
524
- result.error.assistant_outcome || ProviderCallOutcome.capture(result.response)
525
- else
526
- ProviderCallOutcome.capture(result.response)
527
- end
528
- end
529
-
530
504
  # Canonical runtime recording is independent of Application callback health.
531
505
  # Once an event is observed it is appended even after a listener has failed.
532
506
  def deliver_event(event)
@@ -555,13 +529,13 @@ module Phronomy
555
529
  if @event_sink
556
530
  accepted = @event_sink.post(:application_callback_failed, {failure: failure})
557
531
  unless accepted
558
- Phronomy.configuration.logger&.warn(
532
+ Phronomy::RuntimeSettings.current.logger&.warn(
559
533
  "[Phronomy] Callback failure recorded but could not notify " \
560
534
  "FSMSession #{@event_sink.fsm_session_id}: execution_id=#{@execution_id}"
561
535
  )
562
536
  end
563
537
  end
564
- Phronomy.configuration.logger&.warn(
538
+ Phronomy::RuntimeSettings.current.logger&.warn(
565
539
  "[Phronomy] Application event listener failed: " \
566
540
  "#{failure.error.class}: #{failure.error.message}"
567
541
  )
@@ -1,6 +1,6 @@
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
  module Phronomy
6
6
  module Agent