phronomy 0.26.0 → 0.27.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 (304) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +4 -0
  4. data/VERIFY.sh +27 -27
  5. data/benchmark/bench_agent_invoke.rb +26 -22
  6. data/benchmark/bench_context_assembler.rb +4 -5
  7. data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
  8. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  9. data/docs/architecture/agent-context.md +4 -2
  10. data/docs/architecture/agent-transition-ownership.md +89 -0
  11. data/docs/architecture/before-llm-input.md +6 -0
  12. data/docs/architecture/context-management.md +30 -0
  13. data/docs/architecture/context-preparation-steps.md +90 -0
  14. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  15. data/docs/architecture/execution-metadata-and-values.md +80 -0
  16. data/docs/architecture/generator-verifier-ownership.md +111 -0
  17. data/docs/architecture/multi-agent-handoff.md +8 -2
  18. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  19. data/docs/architecture/persistence.md +27 -4
  20. data/docs/architecture/refactoring-closure.md +334 -0
  21. data/docs/architecture/remaining-refactoring-plan.md +374 -0
  22. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  23. data/docs/architecture/tool-schema-recording-gap.md +50 -0
  24. data/docs/architecture/tracing.md +1 -1
  25. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  26. data/docs/architecture.md +209 -0
  27. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  28. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  29. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  30. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  31. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
  32. data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
  33. data/docs/decisions/032-storage-backend-composition.md +80 -0
  34. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  35. data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
  36. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  37. data/docs/decisions/036-context-contract-ownership.md +86 -0
  38. data/docs/decisions/037-common-definition-ownership.md +62 -0
  39. data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
  40. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
  41. data/docs/decisions/040-configuration-default-composition.md +94 -0
  42. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  43. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  44. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  45. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  46. data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
  47. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  48. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  49. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  50. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  51. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  52. data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
  53. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  54. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  55. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  56. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  57. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  58. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  59. data/docs/decisions/058-neutral-storage-primitives.md +78 -0
  60. data/docs/decisions/README.md +35 -6
  61. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  62. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  63. data/docs/features.md +9 -3
  64. data/docs/getting-started.md +4 -4
  65. data/docs/migrations/0.15.md +5 -0
  66. data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
  67. data/docs/migrations/handoff-runner-multi-agent.md +35 -0
  68. data/docs/migrations/neutral-storage-spi.md +43 -0
  69. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  70. data/docs/migrations/shared-state-multi-agent.md +44 -0
  71. data/docs/migrations/storage-backend-composition.md +117 -0
  72. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  73. data/docs/persistence-backends.md +162 -204
  74. data/docs/runtime-and-concurrency.md +117 -32
  75. data/lib/phronomy/agent/api/agent.rb +17 -0
  76. data/lib/phronomy/agent/async_event_api.rb +2 -2
  77. data/lib/phronomy/agent/base.rb +51 -241
  78. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  79. data/lib/phronomy/agent/context/capability/base.rb +67 -26
  80. data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
  81. data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
  82. data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
  83. data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
  84. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
  85. data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
  86. data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
  87. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
  88. data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
  89. data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
  90. data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
  91. data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
  92. data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
  93. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  94. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
  95. data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
  96. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  97. data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
  98. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
  99. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
  100. data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
  101. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  102. data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
  103. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
  104. data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
  105. data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
  106. data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
  107. data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
  108. data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
  109. data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
  110. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  111. data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
  112. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
  113. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
  114. data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
  115. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  116. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  117. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  118. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  119. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  120. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
  121. data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
  122. data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
  123. data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
  124. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
  125. data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
  126. data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
  127. data/lib/phronomy/agent/persistence/codec.rb +358 -0
  128. data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
  129. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
  130. data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
  131. data/lib/phronomy/agent/persistence/queries.rb +61 -0
  132. data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
  133. data/lib/phronomy/agent/persistence/watermark.rb +27 -0
  134. data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
  135. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
  136. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
  137. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
  138. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
  139. data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
  140. data/lib/phronomy/agent/selection/candidate.rb +1 -1
  141. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  142. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  143. data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
  144. data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
  145. data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
  146. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
  147. data/lib/phronomy/common/configuration_error.rb +7 -0
  148. data/lib/phronomy/common/error.rb +5 -0
  149. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  150. data/lib/phronomy/common/values/serializable.rb +32 -0
  151. data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
  152. data/lib/phronomy/configuration/global_configuration.rb +26 -0
  153. data/lib/phronomy/content_store/storage_schema.rb +11 -0
  154. data/lib/phronomy/content_store/stored_contents.rb +43 -0
  155. data/lib/phronomy/engine/backpressure_error.rb +7 -0
  156. data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
  157. data/lib/phronomy/engine/cancellation_error.rb +7 -0
  158. data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
  159. data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
  160. data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
  161. data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
  162. data/lib/phronomy/engine/event_loop.rb +158 -624
  163. data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
  164. data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
  165. data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
  166. data/lib/phronomy/engine/execution_receiver.rb +65 -0
  167. data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
  168. data/lib/phronomy/engine/fsm_protocol.rb +14 -0
  169. data/lib/phronomy/engine/fsm_session.rb +35 -28
  170. data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
  171. data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
  172. data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
  173. data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
  174. data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
  175. data/lib/phronomy/engine/runtime.rb +80 -84
  176. data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
  177. data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
  178. data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
  179. data/lib/phronomy/engine/task_result.rb +4 -0
  180. data/lib/phronomy/engine/timeout_error.rb +7 -0
  181. data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
  182. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  183. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  184. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  185. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  186. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  187. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  188. data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
  189. data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
  190. data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
  191. data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
  192. data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
  193. data/lib/phronomy/llm_contract/transport_error.rb +7 -0
  194. data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
  195. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
  196. data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
  197. data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
  198. data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
  199. data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
  200. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
  201. data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
  202. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  203. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
  204. data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
  205. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  206. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
  207. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  208. data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
  209. data/lib/phronomy/persistence/api/persistence.rb +140 -0
  210. data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
  211. data/lib/phronomy/persistence_composition/repositories.rb +77 -0
  212. data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
  213. data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
  214. data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
  215. data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
  216. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  217. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  218. data/lib/phronomy/storage/backend.rb +101 -0
  219. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  220. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  221. data/lib/phronomy/storage/blobs.rb +31 -0
  222. data/lib/phronomy/storage/condition.rb +25 -0
  223. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  224. data/lib/phronomy/storage/conflict_error.rb +9 -0
  225. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  226. data/lib/phronomy/storage/entry.rb +33 -0
  227. data/lib/phronomy/storage/guard_ref.rb +13 -0
  228. data/lib/phronomy/storage/not_found_error.rb +9 -0
  229. data/lib/phronomy/storage/record_codec.rb +177 -0
  230. data/lib/phronomy/storage/records.rb +61 -0
  231. data/lib/phronomy/storage/resource.rb +126 -0
  232. data/lib/phronomy/storage/scope.rb +25 -0
  233. data/lib/phronomy/storage/serialization_error.rb +9 -0
  234. data/lib/phronomy/storage/streams.rb +44 -0
  235. data/lib/phronomy/storage/transaction_error.rb +10 -0
  236. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  237. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  238. data/lib/phronomy/storage/validation.rb +53 -0
  239. data/lib/phronomy/storage/view.rb +131 -0
  240. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  241. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
  242. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
  243. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
  244. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
  245. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
  246. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
  247. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  248. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
  249. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  250. data/lib/phronomy/tool/contract/tool_error.rb +7 -0
  251. data/lib/phronomy/tools/agent.rb +1 -1
  252. data/lib/phronomy/version.rb +1 -1
  253. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
  254. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
  255. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  256. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
  257. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
  258. data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
  259. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  260. data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
  261. data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
  262. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
  263. data/lib/phronomy.rb +52 -94
  264. data/scripts/api_snapshot.rb +1 -1
  265. data/scripts/storage_spi_snapshot.rb +36 -0
  266. data/sig/phronomy/agent.rbs +0 -1
  267. data/sig/phronomy/execution_receiver.rbs +34 -0
  268. data/sig/phronomy/handoff.rbs +4 -2
  269. data/sig/phronomy/multi_agent.rbs +18 -0
  270. data/sig/phronomy/persistence.rbs +7 -91
  271. data/sig/phronomy/storage.rbs +174 -0
  272. data/sig/phronomy/tool.rbs +10 -1
  273. metadata +230 -99
  274. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  275. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  276. data/lib/phronomy/agent/recovery_support.rb +0 -504
  277. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  278. data/lib/phronomy/agent/tool_executor.rb +0 -55
  279. data/lib/phronomy/generator_verifier.rb +0 -369
  280. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  281. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  282. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  283. data/lib/phronomy/persistence/in_memory.rb +0 -690
  284. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  285. data/lib/phronomy/persistence.rb +0 -276
  286. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  287. data/lib/phronomy/workflow_recovery.rb +0 -123
  288. /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
  289. /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
  290. /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
  291. /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
  292. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  293. /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
  294. /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
  295. /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
  296. /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
  297. /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
  298. /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
  299. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  300. /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
  301. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
  302. /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
  303. /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
  304. /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
@@ -14,10 +14,10 @@ module Phronomy
14
14
  "name" => tool.name.to_s,
15
15
  "description" => tool.description.to_s,
16
16
  "parameters_schema" => normalize(
17
- tool.respond_to?(:parameters_schema) ? tool.parameters_schema : {}
17
+ tool.parameters_schema
18
18
  ),
19
19
  "provider_options" => normalize(
20
- tool.respond_to?(:provider_options) ? tool.provider_options : {}
20
+ tool.provider_options
21
21
  )
22
22
  }
23
23
  end.freeze
@@ -47,13 +47,13 @@ module Phronomy
47
47
 
48
48
  def initialize(runtime_tools:, definitions:)
49
49
  @runtime_tools = Array(runtime_tools).freeze
50
- @definitions = Immutable.copy(definitions)
50
+ @definitions = Phronomy::Values::Immutable.copy(definitions)
51
51
  validate_unique_names!
52
52
  freeze
53
53
  end
54
54
 
55
55
  def select_definitions(expected_definitions)
56
- expected = Immutable.copy(Array(expected_definitions))
56
+ expected = Phronomy::Values::Immutable.copy(Array(expected_definitions))
57
57
  current_by_name = definitions.each_with_index.to_h do |definition, index|
58
58
  [definition.fetch("name"), [definition, runtime_tools.fetch(index)]]
59
59
  end
@@ -70,6 +70,11 @@ module Phronomy
70
70
  raise Phronomy::ConfigurationError,
71
71
  "ContextPolicy selected Tool not present in current Agent configuration: #{name}"
72
72
  end
73
+ if definition["parameters_schema"] == {} && current_definition["parameters_schema"] != {}
74
+ raise Phronomy::ConfigurationError,
75
+ "Saved Tool definition lacks a verifiable parameters_schema: #{name}; " \
76
+ "finish this in-flight execution on its original version before upgrading"
77
+ end
73
78
  unless Phronomy::CanonicalJSON.dump(current_definition) ==
74
79
  Phronomy::CanonicalJSON.dump(definition)
75
80
  raise Phronomy::ConfigurationError,
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../engine/concurrency/worker_input_restricted"
4
+
5
+ require "digest"
3
6
  require "securerandom"
4
7
 
5
8
  module Phronomy
6
9
  module Agent
7
10
  class ToolInvocation
11
+ include Phronomy::Concurrency::WorkerInputRestricted
12
+
8
13
  AuthorizationOutcome = Data.define(
9
14
  :tool_invocation_id, :decision, :facts, :reason, :error, :cancelled
10
15
  ) do
@@ -74,6 +79,20 @@ module Phronomy
74
79
  :origin,
75
80
  :metadata
76
81
 
82
+ # Stable identity used both before dispatch and when rebuilding facts.
83
+ # This does not construct, authorize, or execute a Tool invocation.
84
+ # @api private
85
+ def self.semantic_id(execution_id:, llm_call_id:, tool_call_id:, tool_name:)
86
+ source = [
87
+ "tool_invocation",
88
+ execution_id.to_s,
89
+ llm_call_id.to_s,
90
+ tool_call_id.to_s,
91
+ tool_name.to_s
92
+ ].join("\0")
93
+ "tool_invocation-#{Digest::SHA256.hexdigest(source)}".freeze
94
+ end
95
+
77
96
  def self.missing(
78
97
  execution_id:,
79
98
  agent:,
@@ -135,6 +154,16 @@ module Phronomy
135
154
  @phase = phase
136
155
  end
137
156
 
157
+ # Restores a newly constructed invocation from materialized saved facts.
158
+ # Recovery owns snapshot decoding and identity matching. This operation
159
+ # owns state application; it neither dispatches nor reevaluates approval.
160
+ # @api private
161
+ def restore_state!(status:, result: nil, approval_item: nil)
162
+ restore_saved_state!(status, result)
163
+ restore_approval_evidence!(approval_item)
164
+ self
165
+ end
166
+
138
167
  def handle_fsm_event(event)
139
168
  case event.type
140
169
  when :authorization_completed
@@ -215,7 +244,7 @@ module Phronomy
215
244
  cancellation_token: @config[:cancellation_token],
216
245
  on_full: :raise
217
246
  ) { evaluator.send(:evaluate_authorization_command, command) }
218
- runtime.event_loop.supervise_agent_operation(@execution_id, operation)
247
+ Phronomy::Agent::ExecutionRegistry.for(runtime.event_loop).supervise_agent_operation(@execution_id, operation)
219
248
  operation.on_complete do |outcome, error|
220
249
  callback.call(
221
250
  error ? evaluator.send(:authorization_failure_result, tool_invocation_id, error) : outcome
@@ -259,7 +288,7 @@ module Phronomy
259
288
  raise Phronomy::ToolError,
260
289
  "Tool #{@tool.class.name}#call_async must return a completion handle"
261
290
  end
262
- runtime.event_loop.supervise_agent_operation(@execution_id, operation)
291
+ Phronomy::Agent::ExecutionRegistry.for(runtime.event_loop).supervise_agent_operation(@execution_id, operation)
263
292
 
264
293
  evaluator = self.class
265
294
  tool_invocation_id = @id.to_s.freeze
@@ -332,7 +361,7 @@ module Phronomy
332
361
  end
333
362
 
334
363
  def tool_schema
335
- @tool&.respond_to?(:params_schema) ? @tool.params_schema : {}
364
+ @tool&.respond_to?(:parameters_schema) ? @tool.parameters_schema : {}
336
365
  end
337
366
 
338
367
  def display_arguments
@@ -345,6 +374,40 @@ module Phronomy
345
374
 
346
375
  private
347
376
 
377
+ def restore_saved_state!(status, result)
378
+ case status
379
+ when :awaiting_approval
380
+ validate! unless terminal?
381
+ @final_decision = :require_approval
382
+ mark_awaiting_approval!
383
+ when :authorized
384
+ validate! unless terminal?
385
+ @final_decision = :allow
386
+ mark_authorized!
387
+ when :completed
388
+ @result = result
389
+ @status = :completed
390
+ when :rejected
391
+ mark_rejected!
392
+ when :failed
393
+ mark_framework_failed!(
394
+ Phronomy::ToolError.new("durably restored Tool preflight failure")
395
+ )
396
+ when :cancelled
397
+ mark_cancelled!
398
+ else
399
+ raise Phronomy::ExecutionRehydrationRequiredError,
400
+ "unsupported durable Tool snapshot state: #{status.inspect}"
401
+ end
402
+ end
403
+
404
+ def restore_approval_evidence!(item)
405
+ return unless item
406
+
407
+ @facts = immutable_copy(item.facts)
408
+ @authorization_reason = item.reason
409
+ end
410
+
348
411
  def authorization_command
349
412
  definition = @agent.class.agent_definition
350
413
 
@@ -490,24 +553,7 @@ module Phronomy
490
553
  private_class_method :immutable_command_copy
491
554
 
492
555
  def self.phronomy_managed_live_domain_object?(value)
493
- value.is_a?(Phronomy::Agent::Base) ||
494
- value.is_a?(Phronomy::Agent::AgentRoot) ||
495
- value.is_a?(Phronomy::Agent::AgentExecution) ||
496
- value.is_a?(Phronomy::Agent::AgentInvocation) ||
497
- value.is_a?(Phronomy::Agent::ToolInvocation) ||
498
- value.is_a?(Phronomy::Agent::JournalProjection) ||
499
- value.is_a?(Phronomy::Agent::ExecutionCoordinator) ||
500
- value.is_a?(Phronomy::Agent::Context::Capability::Base) ||
501
- value.is_a?(Phronomy::Workflow) ||
502
- value.is_a?(Phronomy::WorkflowRunner) ||
503
- value.is_a?(Phronomy::WorkflowContext) ||
504
- value.is_a?(Phronomy::Runtime) ||
505
- value.is_a?(Phronomy::TaskResult) ||
506
- value.is_a?(Phronomy::EventLoop) ||
507
- value.is_a?(Phronomy::FSMSession) ||
508
- value.is_a?(Phronomy::FSMSession::EventSink) ||
509
- value.is_a?(Phronomy::Concurrency::CancellationToken) ||
510
- value.is_a?(Phronomy::Concurrency::OffloadPool)
556
+ value.is_a?(Phronomy::Concurrency::WorkerInputRestricted)
511
557
  end
512
558
  private_class_method :phronomy_managed_live_domain_object?
513
559
 
@@ -551,7 +597,7 @@ module Phronomy
551
597
 
552
598
  def start_async_tool_operation(runtime)
553
599
  if uses_default_call_async?
554
- Phronomy::Agent::ToolExecutor.call_async(
600
+ Phronomy::Agent::Context::Capability::ToolExecutor.call_async(
555
601
  tool: @tool,
556
602
  args: @arguments,
557
603
  cancellation_token: @config[:cancellation_token],
@@ -665,18 +711,7 @@ module Phronomy
665
711
  end
666
712
 
667
713
  def immutable_copy(value)
668
- case value
669
- when Hash
670
- value.each_with_object({}) do |(key, item), result|
671
- result[immutable_copy(key)] = immutable_copy(item)
672
- end.freeze
673
- when Array
674
- value.map { |item| immutable_copy(item) }.freeze
675
- when String
676
- value.dup.freeze
677
- else
678
- value
679
- end
714
+ Phronomy::Values::Immutable.copy(value)
680
715
  end
681
716
 
682
717
  def redact_for_display(value)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "error"
4
+
5
+ module Phronomy
6
+ class ConfigurationError < Error; end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ class Error < StandardError; end
5
+ end
@@ -1,10 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../canonical_json"
4
+
3
5
  module Phronomy
4
- module Agent
6
+ module Values
7
+ # Shared value operations for snapshots, recovery facts, and result views.
8
+ # Hash, Array, and String trees are copied and frozen; other values retain
9
+ # their identity. Canonical JSON validation is a separate operation.
10
+ # @api private
5
11
  module Immutable
6
12
  module_function
7
13
 
14
+ # @api private
8
15
  def copy(value)
9
16
  case value
10
17
  when Hash
@@ -20,6 +27,7 @@ module Phronomy
20
27
  end
21
28
  end
22
29
 
30
+ # @api private
23
31
  def validate_canonical_json!(value, label: "value")
24
32
  Phronomy::CanonicalJSON.dump(value)
25
33
  true
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Values
5
+ # Prepares a Ruby value tree for JSON serialization. Hash keys and Symbol
6
+ # values become Strings; containers are rebuilt and scalar objects retained.
7
+ # This neither freezes values nor validates canonical JSON numbers/encoding.
8
+ # @api private
9
+ module Serializable
10
+ module_function
11
+
12
+ def convert(value, unsupported_message:)
13
+ case value
14
+ when Hash
15
+ value.to_h { |key, child| [key.to_s, convert(child, unsupported_message: unsupported_message)] }
16
+ when Array
17
+ value.map { |child| convert(child, unsupported_message: unsupported_message) }
18
+ when String, Integer, Float, TrueClass, FalseClass, NilClass
19
+ value
20
+ when Symbol
21
+ value.to_s
22
+ else
23
+ if value.respond_to?(:to_h)
24
+ convert(value.to_h, unsupported_message: unsupported_message)
25
+ else
26
+ raise ArgumentError, "#{unsupported_message}: #{value.class}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -6,13 +6,23 @@ module Phronomy
6
6
  STREAM_CALLBACK_ERROR_POLICIES = %i[report fail_task].freeze
7
7
  private_constant :STREAM_CALLBACK_ERROR_POLICIES
8
8
 
9
+ DEFAULT_FACTORIES = {}
10
+ private_constant :DEFAULT_FACTORIES
11
+
12
+ # Bind fresh-instance factories once during application loading. Concrete
13
+ # component selection belongs to runtime_composition, not configuration.
14
+ # Applications replace instances through the existing configuration writers.
15
+ # @api private
16
+ def self.install_default_factories(tracer:, llm_adapter:)
17
+ DEFAULT_FACTORIES.replace(tracer: tracer, llm_adapter: llm_adapter).freeze
18
+ nil
19
+ end
20
+
9
21
  attr_accessor :default_model
10
22
  attr_accessor :default_embedding_model
11
23
  attr_accessor :tracer
12
24
  attr_accessor :before_llm_input
13
- attr_accessor :default_output_reserve
14
25
  attr_accessor :recursion_limit
15
- attr_accessor :parallel_tool_execution
16
26
  attr_accessor :trace_pii
17
27
  attr_accessor :logger
18
28
  attr_accessor :event_loop_stop_grace_seconds
@@ -40,11 +50,10 @@ module Phronomy
40
50
 
41
51
  def initialize
42
52
  @recursion_limit = 25
43
- @tracer = Phronomy::Tracing::NullTracer.new
53
+ @tracer = DEFAULT_FACTORIES.fetch(:tracer).call
44
54
  @trace_pii = false
45
- @parallel_tool_execution = false
46
55
  @event_loop_stop_grace_seconds = 5
47
- @llm_adapter = Phronomy::LLMAdapter::RubyLLM.new
56
+ @llm_adapter = DEFAULT_FACTORIES.fetch(:llm_adapter).call
48
57
  @event_loop_starvation_threshold_seconds = nil
49
58
  @event_loop_dispatch_threshold_seconds = nil
50
59
  @stream_callback_error_policy = :report
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Global configuration access, replacement, and scoped overrides.
4
+ # Explicitly loaded by the application entry point; not a common definition.
5
+ module Phronomy
6
+ class << self
7
+ def configuration
8
+ @configuration ||= Configuration.new
9
+ end
10
+
11
+ def configure
12
+ yield configuration
13
+ end
14
+
15
+ def reset_configuration!
16
+ @configuration = Configuration.new
17
+ end
18
+
19
+ def with_configuration
20
+ original = @configuration&.dup
21
+ yield configuration
22
+ ensure
23
+ @configuration = original
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module ContentStore
5
+ # @api private
6
+ module StorageSchema
7
+ CONTENTS = Phronomy::Storage::Resource.new(id: "content.blobs", kind: :blobs,
8
+ attributes: {canonicalization_version: :integer})
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module ContentStore
5
+ # Content identity and digest validation belong to ContentStore, not Blobs.
6
+ # @api private
7
+ class StoredContents < Base
8
+ def initialize(view) = @view = view
9
+
10
+ def put(bytes, canonicalization_version:)
11
+ value = String(bytes).b
12
+ id = content_id_for(value)
13
+ @view.atomic do |bound|
14
+ blob = bound.blobs(StorageSchema::CONTENTS).put_if_absent(key: id, bytes: value,
15
+ attributes: {canonicalization_version: Integer(canonicalization_version)})
16
+ verify!(blob, id)
17
+ id
18
+ end
19
+ rescue Phronomy::Storage::BlobConflictError => error
20
+ raise IntegrityError, error.message
21
+ end
22
+
23
+ def fetch(content_id)
24
+ id = content_id.to_s
25
+ @view.atomic do |bound|
26
+ blob = bound.blobs(StorageSchema::CONTENTS).fetch(id)
27
+ verify!(blob, id)
28
+ blob.bytes.dup
29
+ end
30
+ end
31
+
32
+ def exist?(content_id) = @view.blobs(StorageSchema::CONTENTS).exist?(content_id.to_s)
33
+
34
+ private
35
+
36
+ def verify!(blob, id)
37
+ unless blob.key == id && content_id_for(blob.bytes) == id
38
+ raise IntegrityError, "content digest mismatch: #{id}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../common/error"
4
+
5
+ module Phronomy
6
+ class BackpressureError < Error; end
7
+ end
@@ -22,7 +22,7 @@ module Phronomy
22
22
 
23
23
  begin
24
24
  unless invocation_context.nil?
25
- binding = Execution.__operation_binding(invocation_context: invocation_context,
25
+ binding = Concurrency::OperationBinding.new(invocation_context: invocation_context,
26
26
  cancellation_token: cancellation_token)
27
27
  end
28
28
  result = Phronomy::Runtime.instance.offload.submit(
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../common/error"
4
+
5
+ module Phronomy
6
+ class CancellationError < Error; end
7
+ end
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "worker_input_restricted"
4
+
3
5
  module Phronomy
4
6
  module Concurrency
5
7
  # Cooperative cancellation token for Agent/Tool work.
6
8
  class CancellationToken
9
+ include Phronomy::Concurrency::WorkerInputRestricted
10
+
7
11
  # Creates a token that expires after +seconds+ measured with the monotonic clock.
8
12
  # @api public
9
13
  def self.timeout_after(seconds)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "worker_input_restricted"
4
+
3
5
  module Phronomy
4
6
  module Concurrency
5
7
  # A bounded, observable thread pool for synchronous work that must not run on
@@ -41,6 +43,8 @@ module Phronomy
41
43
  # task = pool.submit(timeout: 30, cancellation_token: token) { expensive_call }
42
44
  # result = task.wait_result
43
45
  class OffloadPool
46
+ include Phronomy::Concurrency::WorkerInputRestricted
47
+
44
48
  # Private execution record for one submitted synchronous operation.
45
49
  #
46
50
  # Caller-facing completion is represented exclusively by {Phronomy::TaskResult}.
@@ -4,7 +4,7 @@ module Phronomy
4
4
  module Concurrency
5
5
  # Connects explicit invocation controls before operation admission. Its token
6
6
  # is private: cancelling it never cancels the application's shared tokens.
7
- # Used by Execution's Agent and Blocking adapters; it owns no worker.
7
+ # Used by Agent, Blocking and Orchestrator admission; it owns no worker.
8
8
  # @api private
9
9
  class OperationBinding
10
10
  attr_reader :token, :scope
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Concurrency
5
+ # Marks framework-managed objects excluded from authorization worker value
6
+ # snapshots and application behavior handles. Each owning type opts in.
7
+ # This methodless contract does not validate arbitrary object graphs or
8
+ # restrict every OffloadPool command. Application-owned opaque values retain
9
+ # their existing contract (ADR-024/045).
10
+ # @api private
11
+ module WorkerInputRestricted
12
+ end
13
+ end
14
+ end