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
@@ -1,276 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- class Persistence
5
- class ConflictError < Phronomy::Error; end
6
- class NotFoundError < Phronomy::Error; end
7
- class UnsupportedBackendError < Phronomy::Error; end
8
- class SerializationError < Phronomy::Error; end
9
-
10
- REQUIRED_CAPABILITIES = {
11
- atomic_all: true,
12
- atomic_admission: true,
13
- optimistic_revision: true
14
- }.freeze
15
-
16
- # Content-addressed immutable content repository. ContentStore has its own
17
- # codec/canonicalization boundary and is not wrapped in DurableRecord.
18
- #
19
- # @return [Object]
20
- # @api public
21
- attr_reader :contents
22
-
23
- # Runtime/domain-facing AgentRoot repository. The backend repository supplied
24
- # to #initialize is record-oriented; this facade owns encode/decode.
25
- #
26
- # @return [Object]
27
- # @api public
28
- attr_reader :agents
29
-
30
- # Runtime/domain-facing append-only Agent Journal repository.
31
- #
32
- # @return [Object]
33
- # @api public
34
- attr_reader :journals
35
-
36
- # Runtime/domain-facing AgentExecution repository.
37
- #
38
- # @return [Object]
39
- # @api public
40
- attr_reader :executions
41
-
42
- # Runtime/domain-facing durable Workflow snapshot repository.
43
- #
44
- # @return [Object]
45
- # @api public
46
- attr_reader :workflow_states
47
-
48
- # Purpose-specific durable Handoff and Team repositories in atomic_all.
49
- # @api public
50
- attr_reader :handoff_states, :teams, :team_executions
51
-
52
- # Read-only exact Agent execution result; never creates a live Agent owner.
53
- # Result is nil until a result_ref exists; errors remain canonical data.
54
- # @api public
55
- def execution_result(execution_id)
56
- assert_observation_thread!
57
- execution = executions.load(execution_id)
58
- {
59
- execution_id: execution.execution_id, agent_id: execution.agent_id,
60
- status: execution.status, phase: execution.phase,
61
- result_ref: execution.result_ref, error_ref: execution.error_ref,
62
- result: execution.result_ref && contents.fetch_text(execution.result_ref),
63
- error: execution.error_ref && contents.fetch_json(execution.error_ref)
64
- }.then { |value| Phronomy::Agent::Immutable.copy(value) }
65
- end
66
-
67
- # Follows one exact Handoff turn without loading any Agent or graph.
68
- # A committed absent Target reservation remains active; failed reads raise.
69
- # @api public
70
- def handoff_result(execution_id, main_agent_id: nil)
71
- assert_observation_thread!
72
- anchor = main_agent_id&.to_s
73
- seen = {}
74
- current = execution_id.to_s
75
- reserved_agent_id = nil
76
- loop do
77
- raise Phronomy::Persistence::SerializationError, "Cyclic durable Handoff chain" if seen[current]
78
- seen[current] = true
79
- begin
80
- execution = executions.load(current)
81
- rescue Phronomy::Persistence::NotFoundError
82
- routing = handoff_states.load(anchor)
83
- if routing && Array(routing.metadata["cancelled_execution_ids"]).include?(current)
84
- return {execution_id: current, agent_id: reserved_agent_id, status: :cancelled, result: nil, error: nil}.freeze
85
- end
86
- if reserved_agent_id && routing && routing.phase != "stable" && routing.pending_target_execution_id == current
87
- return {execution_id: current, agent_id: reserved_agent_id, status: :active,
88
- phase: :target_pending, reserved: true, result: nil, error: nil}.freeze
89
- end
90
- raise
91
- end
92
- anchor ||= execution.metadata.dig("coordination", "main_agent_id")
93
- unless anchor && execution.metadata.dig("coordination", "main_agent_id") == anchor
94
- raise Phronomy::Persistence::ConflictError, "Execution does not belong to this Handoff anchor"
95
- end
96
- return execution_result(current) unless execution.status == :handed_off
97
- reserved_agent_id = execution.metadata.fetch("handoff_target_agent_id")
98
- current = execution.metadata.fetch("handoff_target_execution_id")
99
- end
100
- end
101
-
102
- # Lists retained active and terminal executions in lexical ID order.
103
- # after is an exclusive ID cursor; discovery does not imply request dedup.
104
- # @api public
105
- def list_executions(agent_id, after: nil, limit: 100)
106
- assert_observation_thread!
107
- executions.list(agent_id, after: after, limit: limit)
108
- end
109
-
110
- # Read-only exact Team result, independent of current Team class/Proc wiring.
111
- # @api public
112
- def team_execution_result(team_execution_id)
113
- assert_observation_thread!
114
- execution = team_executions.load(team_execution_id)
115
- {
116
- team_execution_id: execution.team_execution_id, team_id: execution.team_id,
117
- status: execution.status, phase: execution.phase,
118
- result_ref: execution.result_ref, error_ref: execution.error_ref,
119
- result: execution.result_ref && contents.fetch_json(execution.result_ref),
120
- error: execution.error_ref && contents.fetch_json(execution.error_ref)
121
- }.then { |value| Phronomy::Agent::Immutable.copy(value) }
122
- end
123
-
124
- # Lists retained Team runs; no continuation or callback delivery occurs.
125
- # @api public
126
- def list_team_executions(team_id, after: nil, limit: 100)
127
- assert_observation_thread!
128
- team_executions.list(team_id, after: after, limit: limit)
129
- end
130
-
131
- # Initializes a Persistence backend from record-oriented storage
132
- # repositories.
133
- #
134
- # Except for +contents+, backend repositories exchange
135
- # {Phronomy::Persistence::DurableRecord} values. Phronomy's repository
136
- # facades own current-format validation and domain-object encode/decode.
137
- #
138
- # Identity, revision, admission, and index metadata needed by a Backend is
139
- # passed explicitly as repository arguments. A Backend must not inspect
140
- # DurableRecord#payload to rediscover Phronomy domain semantics.
141
- #
142
- # Required raw repository shapes:
143
- # - agents:
144
- # create(agent_id:, agent_revision:, record:), load(id),
145
- # save(id, expected_revision:, next_revision:, record:), delete(id)
146
- # - journals:
147
- # append(id, expected_position:, records:, record_ids:), read/head/delete
148
- # - executions:
149
- # create_active(execution_id:, agent_id:, execution_revision:, record:),
150
- # load(id), save(id, expected_revision:, next_revision:, agent_id:,
151
- # active:, record:), list_active/delete/delete_for_agent/assert_idle!
152
- # - workflow_states:
153
- # load(id), save(id, expected_revision:, next_revision:, record:), delete
154
- #
155
- # Subclasses normally construct backend-specific raw repository objects and
156
- # call +super+. Construction fails fast when required capabilities are not
157
- # advertised.
158
- #
159
- # @api public
160
- def initialize(contents:, agents:, journals:, executions:, workflow_states:, handoff_states:, teams:, team_executions:)
161
- @contents = contents
162
- @agents = RepositoryFacades::Agents.new(agents)
163
- @journals = RepositoryFacades::Journals.new(journals)
164
- @executions = RepositoryFacades::Executions.new(executions)
165
- @workflow_states = RepositoryFacades::WorkflowStates.new(workflow_states)
166
- @handoff_states = RepositoryFacades::HandoffStates.new(handoff_states)
167
- @teams = RepositoryFacades::Teams.new(teams)
168
- @team_executions = RepositoryFacades::TeamExecutions.new(team_executions)
169
- validate_capabilities!
170
- end
171
-
172
- # Declares storage semantics provided by this backend.
173
- #
174
- # Required meanings:
175
- # - +atomic_all+: all durable repositories can participate in one atomic
176
- # transaction domain.
177
- # - +atomic_admission+: Agent execution admission is atomic; at most one
178
- # active/suspended execution may be admitted for one Agent. This does not
179
- # mean cross-process Workflow admission or distributed locking.
180
- # - +optimistic_revision+: Agent, Execution, Workflow revision checks and
181
- # Journal position checks provide compare-and-swap conflict detection.
182
- #
183
- # @return [Hash{Symbol => Boolean}]
184
- # @api public
185
- def capabilities
186
- {
187
- atomic_all: false,
188
- atomic_admission: false,
189
- optimistic_revision: false
190
- }.freeze
191
- end
192
-
193
- # Executes one atomic durable transaction.
194
- #
195
- # The yielded object is a transaction-scoped Persistence view exposing the
196
- # same domain-facing repository facades. Its underlying backend repositories
197
- # remain DurableRecord-oriented.
198
- #
199
- # If the block raises, mutations made through the transaction view must not
200
- # be committed. Storage failures whose commit outcome is fundamentally
201
- # unknown remain backend/database failures; Phronomy does not claim
202
- # exactly-once semantics for such failures.
203
- #
204
- # @yieldparam transaction_view [Object]
205
- # @return [Object] the block result
206
- # @raise [UnsupportedBackendError] when atomic transactions are unavailable
207
- # @api public
208
- def transaction
209
- raise UnsupportedBackendError, "#{self.class} does not provide atomic_all"
210
- end
211
-
212
- # Backend SPI helper for transaction implementations whose transaction-scoped
213
- # raw repositories differ from the root repository objects.
214
- #
215
- # +watermark+ is a transaction-scoped object responding to
216
- # +assert_agent_watermark!+. The returned view owns the same Phronomy codec
217
- # facades as the root Persistence instance, so backend authors never need to
218
- # instantiate RepositoryFacades directly.
219
- #
220
- # Backends whose repository objects are already transaction-scoped may yield
221
- # +self+ and need not call this helper.
222
- #
223
- # @api public
224
- def build_transaction_view(
225
- contents:,
226
- agents:,
227
- journals:,
228
- executions:,
229
- workflow_states:,
230
- handoff_states:, teams:, team_executions:,
231
- watermark:
232
- )
233
- RepositoryFacades::View.new(
234
- contents: contents,
235
- agents: agents,
236
- journals: journals,
237
- executions: executions,
238
- workflow_states: workflow_states,
239
- handoff_states: handoff_states, teams: teams, team_executions: team_executions,
240
- watermark: watermark
241
- )
242
- end
243
-
244
- # Verifies that a live Agent still owns the durable base it hydrated.
245
- #
246
- # This is a Backend SPI operation invoked by Phronomy at durable barriers.
247
- # Ordinary application code should not call it directly. The backend must
248
- # compare the stored Agent revision and current Journal position against the
249
- # supplied watermark in the same storage consistency view used by subsequent
250
- # writes in the surrounding transaction.
251
- #
252
- # @api public
253
- def assert_agent_watermark!(agent_id:, agent_revision:, journal_position:)
254
- raise UnsupportedBackendError,
255
- "#{self.class} does not provide Agent durable-watermark checks"
256
- end
257
-
258
- private
259
-
260
- def assert_observation_thread!
261
- if Phronomy::Runtime.in_event_loop_context?
262
- raise Phronomy::EventLoopReentrancyError, "Persistence observation cannot block EventLoop"
263
- end
264
- end
265
-
266
- def validate_capabilities!
267
- missing = REQUIRED_CAPABILITIES.reject do |key, value|
268
- capabilities[key] == value
269
- end
270
- return if missing.empty?
271
-
272
- raise UnsupportedBackendError,
273
- "Persistence backend lacks required capabilities: #{missing.keys.join(", ")}"
274
- end
275
- end
276
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Patches for upstream ruby_llm bugs that have not yet been released.
4
- # Remove each patch once the fix is available in a published gem version.
5
-
6
- # Guard: apply monkey-patches only to affected ruby_llm versions so that
7
- # upgrading the gem does not silently keep dead overrides in place.
8
- if Gem::Version.new(RubyLLM::VERSION) <= Gem::Version.new("1.15.0")
9
- module RubyLLM
10
- module Streaming
11
- private
12
-
13
- # Upstream ruby_llm <= 1.15.0 assumes the SSE error chunk always has two
14
- # lines ("event: error\ndata: {...}") and uses a fixed index [1], which
15
- # raises NoMethodError when some providers (e.g. Qwen) return a single-line
16
- # chunk ("data: {...}"). This patch finds the data line by content instead.
17
- def handle_error_chunk(chunk, env)
18
- data_line = chunk.split("\n").find { |l| l.start_with?("data: ") } || chunk.split("\n")[0]
19
- error_data = data_line.delete_prefix("data: ")
20
- parse_error_from_json(error_data, env, "Failed to parse error chunk")
21
- end
22
- end
23
- end
24
- end
@@ -1,123 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # ACS-15 Workflow-side Persistence F1 reconciliation. Workflow hydration and
5
- # orchestration remain owned by WorkflowRunner; this module only replaces the
6
- # terminal durable barrier so response loss is reconciled from authoritative
7
- # durable pre/post state instead of being treated as an ordinary failed save.
8
- # @api private
9
- module WorkflowRecovery
10
- private
11
-
12
- def begin_terminal_persistence_on_event_loop(
13
- execution,
14
- terminal_type:,
15
- context:,
16
- event_sink:
17
- )
18
- runtime = Phronomy::Runtime.instance
19
- event_loop = runtime.event_loop
20
- assert_event_loop!(event_loop)
21
- event_loop.mark_workflow_admission(
22
- execution.workflow_instance_id,
23
- owner_token: execution.owner_token,
24
- state: :persisting_terminal
25
- )
26
-
27
- operation = Phronomy::WorkflowRunner::WorkflowTerminalPersistenceCommand.new(
28
- repository: execution.repository,
29
- workflow_instance_id: execution.workflow_instance_id.to_s.freeze,
30
- expected_revision: execution.expected_revision,
31
- snapshot: deep_immutable_copy(snapshot_for(context))
32
- )
33
-
34
- task = runtime.offload.submit(on_full: :raise) do
35
- revision = operation.repository.save(
36
- operation.workflow_instance_id,
37
- expected_revision: operation.expected_revision,
38
- snapshot: operation.snapshot
39
- )
40
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
41
- outcome: :success,
42
- revision: revision,
43
- error: nil
44
- )
45
- rescue Phronomy::Persistence::ConflictError,
46
- Phronomy::Persistence::NotFoundError,
47
- Phronomy::Persistence::SerializationError,
48
- Phronomy::Persistence::UnsupportedBackendError => error
49
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
50
- outcome: :known_failure,
51
- revision: nil,
52
- error: error
53
- )
54
- rescue => error
55
- reconcile_workflow_terminal_f1(operation, error)
56
- end
57
-
58
- task.on_complete do |result, operation_error|
59
- delivery = if operation_error
60
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
61
- outcome: :outcome_unknown,
62
- revision: nil,
63
- error: operation_error
64
- )
65
- else
66
- result
67
- end
68
- accepted = event_sink.post(:workflow_terminal_persistence_result, delivery)
69
- unless accepted
70
- Phronomy.configuration.logger&.warn(
71
- "[Phronomy] EventLoop rejected Workflow terminal persistence result " \
72
- "for #{execution.workflow_instance_id.inspect}"
73
- )
74
- end
75
- end
76
- terminal_type
77
- end
78
-
79
- def reconcile_workflow_terminal_f1(operation, original_error)
80
- record = operation.repository.load(operation.workflow_instance_id)
81
- case Phronomy::Recovery.compare_revisioned_snapshot(
82
- record: record,
83
- expected_pre_revision: operation.expected_revision,
84
- intended_snapshot: operation.snapshot
85
- )
86
- when :post_state
87
- revision = Phronomy::Recovery.fetch_value(record, :revision)
88
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
89
- outcome: :success,
90
- revision: revision,
91
- error: nil
92
- )
93
- when :pre_state
94
- # The uncertain save is now known not to have committed. Do not blindly
95
- # retry it here; surface a known failure through the ordinary terminal
96
- # barrier semantics.
97
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
98
- outcome: :known_failure,
99
- revision: nil,
100
- error: original_error
101
- )
102
- else
103
- conflict = Phronomy::Persistence::ConflictError.new(
104
- "Workflow terminal Persistence outcome conflicts with both expected " \
105
- "pre-state and intended post-state for #{operation.workflow_instance_id.inspect}"
106
- )
107
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
108
- outcome: :outcome_unknown,
109
- revision: nil,
110
- error: conflict
111
- )
112
- end
113
- rescue => reconciliation_error
114
- Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
115
- outcome: :outcome_unknown,
116
- revision: nil,
117
- error: reconciliation_error
118
- )
119
- end
120
- end
121
- end
122
-
123
- Phronomy::WorkflowRunner.prepend(Phronomy::WorkflowRecovery)
File without changes
File without changes
File without changes