phronomy 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +52 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +28 -7
  6. data/benchmark/bench_agent_invoke.rb +25 -50
  7. data/benchmark/bench_context_assembler.rb +14 -11
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/benchmark/bench_tool_schema.rb +1 -1
  10. data/docs/application-recipes.md +229 -0
  11. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  12. data/docs/architecture/agent-transition-ownership.md +13 -89
  13. data/docs/architecture/backend-groups.md +152 -0
  14. data/docs/architecture/before-llm-input.md +3 -3
  15. data/docs/architecture/context-management.md +1 -1
  16. data/docs/architecture/dx05-agent-scope.md +119 -0
  17. data/docs/architecture/dx05-workflow-task-state.md +134 -0
  18. data/docs/architecture/error-api-review.md +245 -0
  19. data/docs/architecture/execution-abstraction-review.md +88 -0
  20. data/docs/architecture/execution-boundaries.md +28 -0
  21. data/docs/architecture/execution-metadata-and-values.md +6 -0
  22. data/docs/architecture/multi-agent-handoff.md +6 -5
  23. data/docs/architecture/persistence.md +27 -9
  24. data/docs/architecture/r8-unit1.md +104 -0
  25. data/docs/architecture/r8-unit10.md +72 -0
  26. data/docs/architecture/r8-unit11.md +71 -0
  27. data/docs/architecture/r8-unit12.md +67 -0
  28. data/docs/architecture/r8-unit13.md +61 -0
  29. data/docs/architecture/r8-unit14.md +72 -0
  30. data/docs/architecture/r8-unit15.md +65 -0
  31. data/docs/architecture/r8-unit16.md +54 -0
  32. data/docs/architecture/r8-unit17.md +73 -0
  33. data/docs/architecture/r8-unit18.md +92 -0
  34. data/docs/architecture/r8-unit19.md +61 -0
  35. data/docs/architecture/r8-unit2.md +55 -0
  36. data/docs/architecture/r8-unit20.md +51 -0
  37. data/docs/architecture/r8-unit21.md +79 -0
  38. data/docs/architecture/r8-unit22.md +74 -0
  39. data/docs/architecture/r8-unit23.md +81 -0
  40. data/docs/architecture/r8-unit3.md +130 -0
  41. data/docs/architecture/r8-unit4.md +79 -0
  42. data/docs/architecture/r8-unit5.md +115 -0
  43. data/docs/architecture/r8-unit6.md +71 -0
  44. data/docs/architecture/r8-unit7.md +70 -0
  45. data/docs/architecture/r8-unit8.md +78 -0
  46. data/docs/architecture/r8-unit9.md +73 -0
  47. data/docs/architecture/refactoring-closure.md +10 -1
  48. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  49. data/docs/architecture/storage-execution-boundaries.md +54 -0
  50. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  51. data/docs/architecture/tracing.md +1 -1
  52. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  53. data/docs/architecture.md +24 -11
  54. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  55. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  56. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  57. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  58. data/docs/decisions/032-storage-backend-composition.md +5 -0
  59. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  60. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  61. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  62. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  63. data/docs/decisions/040-configuration-default-composition.md +12 -1
  64. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  65. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  66. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  67. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  68. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  69. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  70. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  71. data/docs/decisions/062-content-store-service.md +52 -0
  72. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  73. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  74. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  75. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  76. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  77. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  78. data/docs/decisions/README.md +18 -1
  79. data/docs/execution-boundaries-preview.md +45 -0
  80. data/docs/failure-reason-codes.md +45 -0
  81. data/docs/features.md +12 -4
  82. data/docs/getting-started.md +52 -48
  83. data/docs/migrations/0.22.md +2 -2
  84. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  85. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  86. data/docs/migrations/persistence-failure-contracts.md +67 -0
  87. data/docs/migrations/r8-unit10.md +36 -0
  88. data/docs/migrations/r8-unit11.md +33 -0
  89. data/docs/migrations/r8-unit12.md +31 -0
  90. data/docs/migrations/r8-unit13.md +36 -0
  91. data/docs/migrations/r8-unit14.md +31 -0
  92. data/docs/migrations/r8-unit15.md +31 -0
  93. data/docs/migrations/r8-unit16.md +26 -0
  94. data/docs/migrations/r8-unit17.md +28 -0
  95. data/docs/migrations/r8-unit18.md +29 -0
  96. data/docs/migrations/r8-unit19.md +28 -0
  97. data/docs/migrations/r8-unit20.md +24 -0
  98. data/docs/migrations/r8-unit21.md +28 -0
  99. data/docs/migrations/r8-unit22.md +29 -0
  100. data/docs/migrations/r8-unit23.md +20 -0
  101. data/docs/migrations/r8-unit4.md +67 -0
  102. data/docs/migrations/r8-unit5.md +75 -0
  103. data/docs/migrations/r8-unit6.md +109 -0
  104. data/docs/migrations/r8-unit7.md +31 -0
  105. data/docs/migrations/r8-unit8.md +33 -0
  106. data/docs/migrations/r8-unit9.md +28 -0
  107. data/docs/migrations/storage-async-client.md +103 -0
  108. data/docs/migrations/vector-async-clients.md +110 -0
  109. data/docs/ordered-event-delivery.md +54 -0
  110. data/docs/persistence-backends.md +38 -21
  111. data/docs/runtime-and-concurrency.md +26 -1
  112. data/docs/workflow-completion.md +92 -0
  113. data/gemfiles/http_minimum.gemfile +5 -0
  114. data/lib/phronomy/agent/admission.rb +78 -0
  115. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  116. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  117. data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
  118. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  119. data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
  120. data/lib/phronomy/agent/api/agent.rb +13 -0
  121. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  122. data/lib/phronomy/agent/async_event_api.rb +132 -103
  123. data/lib/phronomy/agent/base.rb +146 -113
  124. data/lib/phronomy/agent/before_llm_input.rb +70 -0
  125. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  126. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  127. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  128. data/lib/phronomy/agent/control_request.rb +21 -0
  129. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  130. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  131. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  132. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  133. data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
  134. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  135. data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
  136. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  137. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
  138. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  139. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  140. data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
  141. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  142. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  143. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
  144. data/lib/phronomy/agent/execution_change.rb +161 -0
  145. data/lib/phronomy/agent/execution_environment.rb +36 -0
  146. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  147. data/lib/phronomy/agent/execution_observation.rb +35 -0
  148. data/lib/phronomy/agent/filterable.rb +188 -0
  149. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  150. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  151. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  152. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  153. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  154. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  155. data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
  156. data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
  157. data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
  158. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
  159. data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
  160. data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
  161. data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
  162. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  163. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  164. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  165. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  166. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  167. data/lib/phronomy/agent/persistence/records.rb +33 -0
  168. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  169. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  170. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  171. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  172. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
  173. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
  174. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
  175. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
  176. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  177. data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
  178. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  179. data/lib/phronomy/agent/retention.rb +17 -0
  180. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  181. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  182. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  183. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  184. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  185. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  186. data/lib/phronomy/agent/settings.rb +47 -0
  187. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  188. data/lib/phronomy/agent/store.rb +253 -0
  189. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
  190. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  191. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  192. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  193. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  194. data/lib/phronomy/common/error.rb +65 -1
  195. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  196. data/lib/phronomy/content_store/base.rb +7 -2
  197. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  198. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  199. data/lib/phronomy/context/assembly.rb +195 -0
  200. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  201. data/lib/phronomy/context/candidate.rb +51 -0
  202. data/lib/phronomy/context/constraint.rb +47 -0
  203. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  204. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  205. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  206. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  207. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  208. data/lib/phronomy/context/default_policy.rb +140 -0
  209. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  210. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  211. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  212. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  213. data/lib/phronomy/context/manifest_error.rb +10 -0
  214. data/lib/phronomy/context/prompt_template.rb +98 -0
  215. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  216. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  217. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  218. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  219. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  220. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  221. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  222. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  223. data/lib/phronomy/embeddings/authentication_error.rb +11 -0
  224. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
  225. data/lib/phronomy/embeddings/base.rb +43 -0
  226. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  227. data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
  228. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  229. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  230. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  231. data/lib/phronomy/engine/diagnostics.rb +1 -1
  232. data/lib/phronomy/engine/event_loop.rb +7 -7
  233. data/lib/phronomy/engine/execution_binding.rb +23 -0
  234. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  235. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  236. data/lib/phronomy/engine/fsm_session.rb +3 -3
  237. data/lib/phronomy/engine/metrics.rb +16 -14
  238. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  239. data/lib/phronomy/engine/runtime.rb +25 -12
  240. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  241. data/lib/phronomy/execution/async_operation.rb +41 -0
  242. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  243. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  244. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  245. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  246. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  247. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  248. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  249. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  250. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  251. data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
  252. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  253. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  254. data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
  255. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  256. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  257. data/lib/phronomy/execution/runnable.rb +24 -0
  258. data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
  259. data/lib/phronomy/execution/wait_policy.rb +24 -0
  260. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
  261. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  262. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  263. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  264. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  265. data/lib/phronomy/generation/low_confidence_error.rb +2 -2
  266. data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
  267. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  268. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  269. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  270. data/lib/phronomy/llm_adapter/base.rb +49 -68
  271. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  272. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  273. data/lib/phronomy/llm_adapter/message.rb +62 -0
  274. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  275. data/lib/phronomy/llm_adapter/request.rb +79 -0
  276. data/lib/phronomy/llm_adapter/response.rb +36 -0
  277. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  278. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  279. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  280. data/lib/phronomy/llm_adapter.rb +3 -16
  281. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  282. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  283. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  284. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  285. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  286. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  287. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  288. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  289. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  290. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  291. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  292. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  293. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  294. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  295. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +60 -44
  296. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  297. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  298. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  299. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  300. data/lib/phronomy/multi_agent/store.rb +156 -0
  301. data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
  302. data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
  303. data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
  304. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  305. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  306. data/lib/phronomy/persistence/content_repository.rb +26 -0
  307. data/lib/phronomy/persistence/errors.rb +16 -0
  308. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  309. data/lib/phronomy/persistence/persistence.rb +23 -0
  310. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  311. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  312. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  313. data/lib/phronomy/persistence/transaction.rb +86 -0
  314. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  315. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  316. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  317. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  318. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  319. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  320. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  321. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  322. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  323. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  324. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  325. data/lib/phronomy/storage/async/async_client.rb +60 -0
  326. data/lib/phronomy/storage/backend.rb +8 -2
  327. data/lib/phronomy/storage/condition_failed_error.rb +2 -2
  328. data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
  329. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  330. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  331. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  332. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  333. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  334. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  335. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  336. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  337. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  338. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  339. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  340. data/lib/phronomy/tool/authorization.rb +77 -0
  341. data/lib/phronomy/tool/base.rb +551 -9
  342. data/lib/phronomy/tool/call_request.rb +40 -0
  343. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  344. data/lib/phronomy/tool/operation.rb +88 -0
  345. data/lib/phronomy/tool/schema.rb +214 -0
  346. data/lib/phronomy/tool/settings.rb +31 -0
  347. data/lib/phronomy/tool/tool_error.rb +7 -0
  348. data/lib/phronomy/tool/tool_executor.rb +58 -0
  349. data/lib/phronomy/tools/agent.rb +22 -90
  350. data/lib/phronomy/tools/mcp.rb +21 -14
  351. data/lib/phronomy/tools/vector_search.rb +4 -4
  352. data/lib/phronomy/tracing/automatic.rb +11 -6
  353. data/lib/phronomy/tracing/base.rb +36 -7
  354. data/lib/phronomy/tracing/observation.rb +37 -0
  355. data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
  356. data/lib/phronomy/tracing/settings.rb +36 -0
  357. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  358. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  359. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  360. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  361. data/lib/phronomy/vector_store/base.rb +118 -49
  362. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  363. data/lib/phronomy/vector_store.rb +2 -17
  364. data/lib/phronomy/version.rb +1 -1
  365. data/lib/phronomy/workflow/completion.rb +11 -0
  366. data/lib/phronomy/workflow/execution/workflow.rb +37 -9
  367. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  368. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  369. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
  370. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
  371. data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
  372. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  373. data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
  374. data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
  375. data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
  376. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  377. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  378. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
  379. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
  380. data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
  381. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  382. data/lib/phronomy.rb +63 -16
  383. data/scripts/api_snapshot.rb +47 -15
  384. data/scripts/check_readme_ruby.rb +24 -29
  385. data/scripts/check_readme_runnable.rb +92 -81
  386. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  387. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  388. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  389. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  390. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  391. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  392. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  393. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  394. data/sig/phronomy/agent/admission.rbs +19 -0
  395. data/sig/phronomy/agent/agent_not_found_error.rbs +6 -0
  396. data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -0
  397. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  398. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  399. data/sig/phronomy/agent/store.rbs +73 -0
  400. data/sig/phronomy/agent/stream_callback_error.rbs +8 -0
  401. data/sig/phronomy/agent.rbs +29 -135
  402. data/sig/phronomy/common.rbs +7 -0
  403. data/sig/phronomy/content_store/contracts.rbs +13 -0
  404. data/sig/phronomy/context.rbs +152 -0
  405. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  406. data/sig/phronomy/embeddings/base.rbs +23 -0
  407. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  408. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  409. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  410. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  411. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  412. data/sig/phronomy/engine/observability.rbs +13 -0
  413. data/sig/phronomy/execution/async_operation.rbs +7 -0
  414. data/sig/phronomy/execution/blocking.rbs +5 -0
  415. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  416. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  417. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  418. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  419. data/sig/phronomy/execution/errors.rbs +7 -0
  420. data/sig/phronomy/execution/execution.rbs +41 -0
  421. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  422. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  423. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  424. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  425. data/sig/phronomy/execution/task_result.rbs +29 -0
  426. data/sig/phronomy/extensions.rbs +1 -21
  427. data/sig/phronomy/filter/filter_block_error.rbs +6 -0
  428. data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
  429. data/sig/phronomy/handoff.rbs +10 -4
  430. data/sig/phronomy/integrations.rbs +14 -0
  431. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  432. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  433. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  434. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  435. data/sig/phronomy/llm_context_window.rbs +10 -0
  436. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  437. data/sig/phronomy/multi_agent/store.rbs +54 -0
  438. data/sig/phronomy/multi_agent/team_busy_error.rbs +8 -0
  439. data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
  440. data/sig/phronomy/multi_agent.rbs +6 -3
  441. data/sig/phronomy/persistence/errors.rbs +18 -0
  442. data/sig/phronomy/persistence/migration.rbs +13 -0
  443. data/sig/phronomy/persistence/transaction.rbs +19 -0
  444. data/sig/phronomy/persistence.rbs +1 -99
  445. data/sig/phronomy/persistence_composition.rbs +19 -0
  446. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  447. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  448. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  449. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +4 -18
  450. data/sig/phronomy/tool.rbs +48 -4
  451. data/sig/phronomy/tracing/observation.rbs +7 -0
  452. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  453. data/sig/phronomy/vector_store/base.rbs +23 -0
  454. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +15 -0
  455. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  456. data/sig/phronomy/workflow/store.rbs +8 -0
  457. data/sig/phronomy/workflow.rbs +5 -1
  458. data/sig/phronomy.rbs +4 -49
  459. metadata +365 -117
  460. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  461. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  462. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  463. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  464. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  465. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  466. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  467. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  468. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  469. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  470. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  471. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  472. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  473. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  474. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  475. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  476. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  477. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  478. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  479. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  480. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  481. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  482. data/lib/phronomy/configuration/configuration.rb +0 -68
  483. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  484. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  485. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  486. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  487. data/lib/phronomy/engine/runnable.rb +0 -54
  488. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  489. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  490. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  491. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  492. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  493. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  494. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  495. data/lib/phronomy/recovery/recovery.rb +0 -186
  496. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  497. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  498. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  499. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  500. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  501. data/sig/phronomy/execution_receiver.rbs +0 -34
  502. data/sig/phronomy/llm_adapter.rbs +0 -11
  503. data/sig/phronomy/runtime.rbs +0 -76
  504. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  505. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  506. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  507. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  508. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  509. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  510. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  511. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  512. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  513. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  514. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  515. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  516. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  517. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -1,186 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Small private Recovery semantic/primitives layer shared by Agent and
5
- # Workflow recovery. Entity-specific orchestration remains outside this module.
6
- # @api private
7
- module Recovery
8
- RESUMABLE = :resumable
9
- RECONCILABLE = :reconcilable
10
- RESOLUTION_REQUIRED = :resolution_required
11
- DISPOSITIONS = [RESUMABLE, RECONCILABLE, RESOLUTION_REQUIRED].freeze
12
-
13
- ALLOWED_OUTCOMES = %i[succeeded failed not_performed].freeze
14
- # Internal shorthand used by the Agent Recovery implementation. This is not
15
- # a public API constant; both names refer to the same frozen value.
16
- OUTCOMES = ALLOWED_OUTCOMES
17
-
18
- MISSING = Object.new.freeze
19
-
20
- Classification = Data.define(
21
- :disposition, :reason, :subject, :allowed_outcomes, :facts
22
- ) do
23
- def initialize(
24
- disposition:,
25
- reason:,
26
- subject: nil,
27
- allowed_outcomes: [],
28
- facts: {}
29
- )
30
- normalized = disposition.to_sym
31
- unless Phronomy::Recovery::DISPOSITIONS.include?(normalized)
32
- raise ArgumentError, "unknown Recovery disposition: #{disposition.inspect}"
33
- end
34
- super(
35
- disposition: normalized,
36
- reason: reason.to_sym,
37
- subject: subject && Phronomy::Recovery.normalize_subject(subject),
38
- allowed_outcomes: Array(allowed_outcomes).map(&:to_sym).freeze,
39
- facts: Phronomy::Values::Immutable.copy(facts || {})
40
- )
41
- end
42
- end
43
-
44
- module_function
45
-
46
- def normalize_outcome(outcome)
47
- normalized = outcome.to_sym
48
- unless OUTCOMES.include?(normalized)
49
- raise ArgumentError, "unsupported Recovery outcome: #{outcome.inspect}"
50
- end
51
- normalized
52
- end
53
-
54
- def validate_resolution_material!(outcome:, result_present:, error_present:)
55
- normalized = normalize_outcome(outcome)
56
- case normalized
57
- when :succeeded
58
- raise ArgumentError, "Recovery :succeeded requires result:" unless result_present
59
- raise ArgumentError, "Recovery :succeeded forbids error:" if error_present
60
- when :failed
61
- raise ArgumentError, "Recovery :failed requires error:" unless error_present
62
- raise ArgumentError, "Recovery :failed forbids result:" if result_present
63
- when :not_performed
64
- if result_present || error_present
65
- raise ArgumentError, "Recovery :not_performed accepts neither result: nor error:"
66
- end
67
- end
68
- true
69
- end
70
-
71
- def normalize_subject(subject)
72
- hash = subject.to_h.transform_keys(&:to_sym)
73
- type = hash.fetch(:type).to_sym
74
- normalized = {type: type}
75
- case type
76
- when :llm_call
77
- normalized[:llm_call_id] = required_id(hash, :llm_call_id)
78
- when :tool_invocation
79
- normalized[:tool_invocation_id] = required_id(hash, :tool_invocation_id)
80
- when :persistence_operation
81
- # Persistence operation references are structural only. Do not introduce
82
- # a generic durable operation/recovery identity here.
83
- normalized[:entity] = hash.fetch(:entity).to_sym
84
- else
85
- raise ArgumentError, "unsupported Recovery subject type: #{type.inspect}"
86
- end
87
- normalized.freeze
88
- end
89
-
90
- def subject_key(subject)
91
- normalized = normalize_subject(subject)
92
- case normalized.fetch(:type)
93
- when :llm_call
94
- "llm_call:#{normalized.fetch(:llm_call_id)}"
95
- when :tool_invocation
96
- "tool_invocation:#{normalized.fetch(:tool_invocation_id)}"
97
- when :persistence_operation
98
- "persistence_operation:#{normalized.fetch(:entity)}"
99
- end
100
- end
101
-
102
- def subject_equal?(left, right)
103
- normalize_subject(left) == normalize_subject(right)
104
- rescue ArgumentError, KeyError
105
- false
106
- end
107
-
108
- # Compare authoritative current state with a known pre/post revision pair.
109
- # This is deliberately small: callers still validate entity-specific content.
110
- def compare_revisions(current_revision:, expected_pre_revision:, intended_post_revision:)
111
- current = current_revision
112
- return :post_state if current == intended_post_revision
113
- return :pre_state if current == expected_pre_revision
114
-
115
- :conflict
116
- end
117
-
118
- # Generic F1 helper for revisioned snapshot repositories such as Workflow.
119
- # Some repositories return a newly allocated revision only after save, so
120
- # callers may not know the intended post revision in advance. In that case
121
- # the intended snapshot plus a revision different from the expected pre
122
- # revision identifies the post-state.
123
- def compare_revisioned_snapshot(
124
- record:,
125
- expected_pre_revision:,
126
- intended_snapshot:,
127
- intended_post_revision: nil
128
- )
129
- return :pre_state if record.nil? && expected_pre_revision.nil?
130
- return :conflict if record.nil?
131
-
132
- revision = fetch_value(record, :revision)
133
- snapshot = fetch_value(record, :snapshot)
134
- normalized_snapshot = normalize_value(snapshot)
135
- normalized_intended = normalize_value(intended_snapshot)
136
-
137
- if intended_post_revision
138
- if revision == intended_post_revision &&
139
- normalized_snapshot == normalized_intended
140
- return :post_state
141
- end
142
- elsif normalized_snapshot == normalized_intended &&
143
- revision != expected_pre_revision
144
- return :post_state
145
- end
146
-
147
- return :pre_state if revision == expected_pre_revision
148
-
149
- :conflict
150
- end
151
-
152
- def normalize_value(value)
153
- case value
154
- when Hash
155
- value.each_with_object({}) do |(key, child), result|
156
- result[key.to_s] = normalize_value(child)
157
- end
158
- when Array
159
- value.map { |child| normalize_value(child) }
160
- when Symbol
161
- value.to_s
162
- else
163
- value
164
- end
165
- end
166
-
167
- def fetch_value(record, key)
168
- return nil unless record
169
- return record.public_send(key) if record.respond_to?(key)
170
- return record[key] if record.respond_to?(:key?) && record.key?(key)
171
- string_key = key.to_s
172
- return record[string_key] if record.respond_to?(:key?) && record.key?(string_key)
173
-
174
- nil
175
- end
176
-
177
- def required_id(hash, key)
178
- value = hash.fetch(key)
179
- text = value.to_s
180
- raise ArgumentError, "#{key} must not be empty" if text.empty?
181
-
182
- text.freeze
183
- end
184
- private_class_method :required_id
185
- end
186
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../common/error"
4
-
5
- module Phronomy
6
- class ToolError < Error; end
7
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module VectorStore
5
- module Embeddings
6
- # Public extension SPI for embedding adapters.
7
- #
8
- # Concrete implementations override {#embed}. Phronomy owns the async
9
- # bridge: {#embed_async} routes the synchronous implementation through the
10
- # bounded OffloadPool and returns a {Phronomy::TaskResult}.
11
- #
12
- # @api public
13
- class Base
14
- # Embed the given text and return a vector representation.
15
- #
16
- # @param text [String] the text to embed
17
- # @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
18
- # @return [Array<Float>] the embedding vector
19
- # @api public
20
- def embed(text, cancellation_token = nil)
21
- cancellation_token&.raise_if_cancelled!
22
- raise NotImplementedError, "#{self.class}#embed is not implemented"
23
- end
24
-
25
- # Submits an {#embed} call to {OffloadPool}.
26
- #
27
- # @param text [String]
28
- # @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
29
- # @param timeout [Numeric, nil] operation-wide submit timeout
30
- # @return [Phronomy::TaskResult]
31
- # @api public
32
- def embed_async(text, cancellation_token = nil, timeout: nil)
33
- Phronomy::Runtime.instance.offload.submit(
34
- timeout: timeout,
35
- cancellation_token: cancellation_token,
36
- on_full: :raise
37
- ) do
38
- embed(text, cancellation_token)
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module VectorStore
5
- module Embeddings
6
- # Embeddings adapter backed by RubyLLM.
7
- #
8
- # Delegates to +RubyLLM.embed+ and returns the resulting vector as an
9
- # +Array<Float>+.
10
- #
11
- # @example Default model
12
- # embeddings = Phronomy::VectorStore::Embeddings::RubyLLMEmbeddings.new
13
- # vector = embeddings.embed("Hello, world!")
14
- #
15
- # @example Explicit model
16
- # embeddings = Phronomy::VectorStore::Embeddings::RubyLLMEmbeddings.new(model: "text-embedding-3-small")
17
- # vector = embeddings.embed("Hello, world!")
18
- class RubyLLMEmbeddings < Base
19
- # @param model [String, nil] embedding model identifier; nil uses the RubyLLM default
20
- # @param provider [Symbol, nil] provider override (e.g. :openai); nil uses the RubyLLM default
21
- # @param assume_model_exists [Boolean] when true, skips RubyLLM model-registry validation
22
- # (useful for locally hosted models not in the registry)
23
- # @api public
24
- def initialize(model: nil, provider: nil, assume_model_exists: false)
25
- @model = model
26
- @provider = provider
27
- @assume_model_exists = assume_model_exists
28
- end
29
-
30
- # Embed text via RubyLLM.
31
- #
32
- # @param text [String]
33
- # @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil] optional; raises CancellationError when cancelled
34
- # @return [Array<Float>]
35
- # @api public
36
- def embed(text, cancellation_token = nil)
37
- cancellation_token&.raise_if_cancelled!
38
- opts = {}
39
- opts[:model] = @model if @model
40
- opts[:provider] = @provider if @provider
41
- opts[:assume_model_exists] = true if @assume_model_exists
42
- RubyLLM.embed(text, **opts).vectors
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,205 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "state_machines"
4
-
5
- module Phronomy
6
- class Workflow
7
- # Builds the anonymous state-machine Class used by WorkflowRunner.
8
- #
9
- # This class compiles Workflow topology into state_machines declarations.
10
- # It intentionally does not await Tasks, register completion callbacks,
11
- # cancel external work, or interpret application event payloads.
12
- #
13
- # @api private
14
- class PhaseMachineBuilder
15
- def initialize(
16
- entry_point:,
17
- declared_states:,
18
- wait_state_names:,
19
- external_events:,
20
- entry_actions:,
21
- auto_transitions:,
22
- exit_actions:
23
- )
24
- @entry_point = entry_point
25
- @declared_states = declared_states
26
- @wait_state_names = wait_state_names
27
- @external_events = external_events
28
- @entry_actions = entry_actions
29
- @auto_transitions = auto_transitions
30
- @exit_actions = exit_actions
31
- end
32
-
33
- def build
34
- entry = @entry_point
35
- all_states = (@declared_states + @wait_state_names + [FSMProtocol::FINISH]).uniq
36
- auto_transitions = @auto_transitions
37
- external_events = @external_events
38
- entry_actions = @entry_actions
39
- exit_actions = @exit_actions
40
- condition_builder = method(:build_transition_condition)
41
- entry_callback_builder = method(:build_entry_callback)
42
- exit_callback_builder = method(:build_exit_callback)
43
- transition_callback = build_transition_action_callback
44
-
45
- Class.new do
46
- attr_accessor(
47
- :context,
48
- :current_event,
49
- :selected_transition_action,
50
- :selected_transition_metadata
51
- )
52
-
53
- state_machine :phase, initial: entry do
54
- all_states.each { |state_name| state state_name }
55
-
56
- event :state_completed do
57
- auto_transitions.each do |transition_definition|
58
- transition(
59
- transition_definition[:from] => transition_definition[:to],
60
- :if => condition_builder.call(transition_definition)
61
- )
62
- end
63
- end
64
-
65
- external_events.each do |event_name, transitions|
66
- event event_name do
67
- transitions.each do |transition_definition|
68
- transition(
69
- transition_definition[:from] => transition_definition[:to],
70
- :if => condition_builder.call(transition_definition)
71
- )
72
- end
73
- end
74
- end
75
-
76
- entry_actions.each do |state_name, callables|
77
- callables.each do |callable|
78
- after_transition(
79
- to: state_name,
80
- &entry_callback_builder.call(callable, state_name)
81
- )
82
- end
83
- end
84
-
85
- # Both source exit callbacks and the transition action are
86
- # before_transition callbacks. Register exits first to preserve the
87
- # required exit -> transition action -> entry ordering.
88
- exit_actions.each do |state_name, callables|
89
- callables.each do |callable|
90
- before_transition(
91
- from: state_name,
92
- &exit_callback_builder.call(callable, state_name)
93
- )
94
- end
95
- end
96
-
97
- before_transition(&transition_callback)
98
- end
99
- end
100
- rescue => error
101
- raise ArgumentError, "Failed to build phase machine: #{error.message}"
102
- end
103
-
104
- private
105
-
106
- def build_transition_condition(transition_definition)
107
- guard = transition_definition[:guard]
108
- action = transition_definition[:action]
109
- metadata = {
110
- from: transition_definition[:from],
111
- event: transition_definition[:event],
112
- to: public_destination(transition_definition[:to])
113
- }.freeze
114
-
115
- ->(machine) {
116
- matched =
117
- guard.nil? ||
118
- call_with_optional_event(
119
- guard,
120
- machine.context,
121
- machine.current_event
122
- )
123
-
124
- if matched
125
- machine.selected_transition_action = action
126
- machine.selected_transition_metadata = metadata
127
- end
128
- matched
129
- }
130
- end
131
-
132
- def build_transition_action_callback
133
- ->(machine) {
134
- callable = machine.selected_transition_action
135
- unless callable.nil?
136
- metadata = machine.selected_transition_metadata || {}
137
- result = call_with_optional_event(
138
- callable,
139
- machine.context,
140
- machine.current_event
141
- )
142
- if result.is_a?(Phronomy::TaskResult)
143
- raise Phronomy::InvalidAsyncTransitionActionError,
144
- transition_task_error_message(metadata)
145
- end
146
- machine.context = result if workflow_context_result?(result)
147
- end
148
- }
149
- end
150
-
151
- def build_entry_callback(callable, state_name)
152
- ->(machine) {
153
- result = callable.call(machine.context)
154
- if result.is_a?(Phronomy::TaskResult)
155
- raise Phronomy::InvalidAsyncEntryActionError,
156
- "Entry action for state #{state_name.inspect} returned Phronomy::TaskResult. " \
157
- "Start the asynchronous operation, register its callback/listener, " \
158
- "and return the WorkflowContext or nil."
159
- end
160
- machine.context = result if workflow_context_result?(result)
161
- }
162
- end
163
-
164
- def build_exit_callback(callable, state_name)
165
- ->(machine) {
166
- result = callable.call(machine.context)
167
- if result.is_a?(Phronomy::TaskResult)
168
- raise Phronomy::InvalidAsyncEntryActionError,
169
- "Exit action for state #{state_name.inspect} returned Phronomy::TaskResult. " \
170
- "Exit actions are synchronous Run-to-Completion callbacks."
171
- end
172
- }
173
- end
174
-
175
- def call_with_optional_event(callable, context, event)
176
- parameters =
177
- if callable.respond_to?(:parameters)
178
- callable.parameters
179
- else
180
- callable.method(:call).parameters
181
- end
182
- accepts_event = parameters.length >= 2
183
- accepts_event ? callable.call(context, event) : callable.call(context)
184
- end
185
-
186
- def workflow_context_result?(result)
187
- result.respond_to?(:set_graph_metadata)
188
- end
189
-
190
- def public_destination(destination)
191
- return :__finish__ if destination == FSMProtocol::FINISH
192
-
193
- destination
194
- end
195
-
196
- def transition_task_error_message(metadata)
197
- "Transition action " \
198
- "#{metadata[:from].inspect} --#{metadata[:event].inspect}--> " \
199
- "#{metadata[:to].inspect} returned Phronomy::TaskResult. " \
200
- "Start the asynchronous operation, register its callback/listener, " \
201
- "and return the WorkflowContext or nil."
202
- end
203
- end
204
- end
205
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Domain-owned Workflow metadata, loadable without the Workflow runtime.
5
- # @api private
6
- module WorkflowStorageSchema
7
- STATES = Phronomy::Storage::Resource.new(id: "workflow.states", kind: :records)
8
- end
9
- end
@@ -1,34 +0,0 @@
1
- module Phronomy
2
- # Internal Engine contract (ADR-042); not an application extension SPI.
3
- class ExecutionReceiver
4
- def self.for: (EventLoop event_loop) -> instance
5
- def self.existing_for: (Runtime runtime) -> instance?
6
- def initialize: (event_loop: EventLoop) -> void
7
- def __bound_to?: (EventLoop event_loop) -> bool
8
- def idle?: () -> bool
9
- def deliver: (untyped message) -> untyped
10
- def shutdown: (error: Exception?) -> untyped
11
- def session_retired: (String fsm_session_id, reason: Symbol) -> untyped
12
-
13
- private
14
-
15
- def synchronize: [V] () { () -> V } -> V
16
- def admit: [V] () { () -> V } -> V
17
- def post_message: (untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
18
- def assert_event_loop_thread!: () -> void
19
- end
20
-
21
- class EventLoop
22
- def __execution_receiver: (key: untyped) -> ExecutionReceiver?
23
- def __register_execution_receiver: (key: untyped, receiver: ExecutionReceiver) -> ExecutionReceiver
24
- def __synchronize_execution_state: [V] () { () -> V } -> V
25
- def __admit_execution: [V] (ExecutionReceiver receiver) { () -> V } -> V
26
- def __post_execution: (ExecutionReceiver receiver, untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
27
- def __route_execution_event: (ExecutionReceiver receiver) { () -> untyped } -> bool
28
- def __receiver_cleanup_complete?: () -> bool
29
- end
30
-
31
- class Runtime
32
- def __event_loop_if_initialized: () -> EventLoop?
33
- end
34
- end
@@ -1,11 +0,0 @@
1
- module Phronomy
2
- module LLMAdapter
3
- class Base
4
- def complete: (untyped chat, String? message, ?config: Hash[untyped, untyped]) -> untyped
5
- def stream: (untyped chat, String? message, ?config: Hash[untyped, untyped]) { (untyped chunk) -> void } -> untyped
6
- end
7
-
8
- class RubyLLM < Base
9
- end
10
- end
11
- end
@@ -1,76 +0,0 @@
1
- module Phronomy
2
- class TaskResult[A]
3
- class Outcome[V]
4
- attr_reader index: Integer
5
- attr_reader status: (:completed | :failed | :cancelled | :unfinished)
6
- attr_reader value: V?
7
- attr_reader error: Exception?
8
- end
9
-
10
- def self.completed: [V] (V value, ?name: String?) -> TaskResult[V]
11
- | (?name: String?) -> TaskResult[nil]
12
- def self.failed: (Exception error, ?name: String?) -> TaskResult[untyped]
13
- def self.all_settled: [V] (Array[TaskResult[V]] results) -> TaskResult[Array[Outcome[V]]]
14
- attr_reader name: String?
15
- attr_reader parent: TaskResult[untyped]?
16
-
17
- def status: () -> (:pending | :completed | :failed | :cancelled)
18
- def done?: () -> bool
19
- def alive?: () -> bool
20
- def wait_result: (?timeout: Numeric?) -> A
21
- def on_complete: () { (A?, Exception?) -> void } -> self
22
- def map: [B] () { (A) -> B } -> TaskResult[B]
23
- def flat_map: [B] () { (A) -> TaskResult[B] } -> TaskResult[B]
24
- end
25
-
26
- class Execution
27
- attr_reader invocation_context: InvocationContext
28
-
29
- def self.run_async: [I, V] (Array[I] inputs, ?timeout: Numeric?, ?cancellation_token: Concurrency::CancellationToken?, ?invocation_context: InvocationContext?) { (I, Execution) -> TaskResult[V] } -> TaskResult[Array[TaskResult::Outcome[V]]]
30
- def self.run: [I, V] (Array[I] inputs, ?timeout: Numeric?, ?cancellation_token: Concurrency::CancellationToken?, ?invocation_context: InvocationContext?) { (I, Execution) -> TaskResult[V] } -> Array[TaskResult::Outcome[V]]
31
- def observe: [V] (TaskResult[V] source_result) -> TaskResult[V]
32
- end
33
-
34
- class ExecutionTimeoutError < TimeoutError
35
- attr_reader outcomes: Array[TaskResult::Outcome[untyped]]
36
- def initialize: (?String message, outcomes: Array[TaskResult::Outcome[untyped]]) -> void
37
- end
38
-
39
- class ExecutionCancellationError < CancellationError
40
- attr_reader outcomes: Array[TaskResult::Outcome[untyped]]
41
- def initialize: (?String message, outcomes: Array[TaskResult::Outcome[untyped]]) -> void
42
- end
43
-
44
- module Concurrency
45
- class CancellationToken
46
- def self.timeout_after: (Numeric seconds) -> CancellationToken
47
- def initialize: (?monotonic_deadline: Float?) -> void
48
- def remaining_monotonic_seconds: () -> Float?
49
- def on_cancel: () { () -> void } -> self
50
- def cancel!: () -> self
51
- def cancelled?: () -> bool
52
- def raise_if_cancelled!: (?String message) -> nil
53
- end
54
- end
55
- end
56
-
57
- module Phronomy
58
- class InvocationContext
59
- attr_reader user_id: String?
60
- attr_reader cancellation_token: Concurrency::CancellationToken?
61
- attr_reader deadline: untyped
62
- attr_reader token_budget: Integer?
63
- attr_reader approval_policy: untyped
64
- attr_reader redaction_policy: untyped
65
- attr_reader task_id: String?
66
- attr_reader parent_task_id: String?
67
-
68
- def initialize: (?user_id: String?, ?cancellation_token: Concurrency::CancellationToken?, ?deadline: untyped, ?token_budget: Integer?, ?approval_policy: untyped, ?redaction_policy: untyped, ?task_id: String?, ?parent_task_id: String?) -> void
69
- end
70
- end
71
-
72
- module Phronomy
73
- module Blocking
74
- def self.call_async: [V] (?timeout: Numeric?, ?cancellation_token: Concurrency::CancellationToken?, ?invocation_context: InvocationContext?) { () -> V } -> TaskResult[V]
75
- end
76
- end