phronomy 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +52 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +9 -3
  6. data/benchmark/bench_agent_invoke.rb +25 -50
  7. data/benchmark/bench_context_assembler.rb +14 -11
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/benchmark/bench_tool_schema.rb +1 -1
  10. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  11. data/docs/architecture/agent-transition-ownership.md +13 -89
  12. data/docs/architecture/backend-groups.md +152 -0
  13. data/docs/architecture/before-llm-input.md +3 -3
  14. data/docs/architecture/context-management.md +1 -1
  15. data/docs/architecture/execution-abstraction-review.md +88 -0
  16. data/docs/architecture/execution-boundaries.md +28 -0
  17. data/docs/architecture/execution-metadata-and-values.md +6 -0
  18. data/docs/architecture/multi-agent-handoff.md +6 -5
  19. data/docs/architecture/persistence.md +27 -9
  20. data/docs/architecture/r8-unit1.md +104 -0
  21. data/docs/architecture/r8-unit10.md +72 -0
  22. data/docs/architecture/r8-unit11.md +71 -0
  23. data/docs/architecture/r8-unit12.md +67 -0
  24. data/docs/architecture/r8-unit13.md +61 -0
  25. data/docs/architecture/r8-unit14.md +72 -0
  26. data/docs/architecture/r8-unit15.md +65 -0
  27. data/docs/architecture/r8-unit16.md +54 -0
  28. data/docs/architecture/r8-unit17.md +73 -0
  29. data/docs/architecture/r8-unit18.md +92 -0
  30. data/docs/architecture/r8-unit19.md +61 -0
  31. data/docs/architecture/r8-unit2.md +55 -0
  32. data/docs/architecture/r8-unit20.md +51 -0
  33. data/docs/architecture/r8-unit21.md +79 -0
  34. data/docs/architecture/r8-unit22.md +74 -0
  35. data/docs/architecture/r8-unit23.md +81 -0
  36. data/docs/architecture/r8-unit3.md +130 -0
  37. data/docs/architecture/r8-unit4.md +79 -0
  38. data/docs/architecture/r8-unit5.md +115 -0
  39. data/docs/architecture/r8-unit6.md +71 -0
  40. data/docs/architecture/r8-unit7.md +70 -0
  41. data/docs/architecture/r8-unit8.md +78 -0
  42. data/docs/architecture/r8-unit9.md +73 -0
  43. data/docs/architecture/refactoring-closure.md +10 -1
  44. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  45. data/docs/architecture/storage-execution-boundaries.md +54 -0
  46. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  47. data/docs/architecture/tracing.md +1 -1
  48. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  49. data/docs/architecture.md +24 -11
  50. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  51. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  52. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  53. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  54. data/docs/decisions/032-storage-backend-composition.md +5 -0
  55. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  56. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  57. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  58. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  59. data/docs/decisions/040-configuration-default-composition.md +12 -1
  60. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  61. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  62. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  63. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  64. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  65. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  66. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  67. data/docs/decisions/062-content-store-service.md +52 -0
  68. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  69. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  70. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  71. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  72. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  73. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  74. data/docs/decisions/README.md +18 -1
  75. data/docs/execution-boundaries-preview.md +45 -0
  76. data/docs/features.md +8 -3
  77. data/docs/getting-started.md +9 -6
  78. data/docs/migrations/0.22.md +2 -2
  79. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  80. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  81. data/docs/migrations/persistence-failure-contracts.md +67 -0
  82. data/docs/migrations/r8-unit10.md +36 -0
  83. data/docs/migrations/r8-unit11.md +33 -0
  84. data/docs/migrations/r8-unit12.md +31 -0
  85. data/docs/migrations/r8-unit13.md +36 -0
  86. data/docs/migrations/r8-unit14.md +31 -0
  87. data/docs/migrations/r8-unit15.md +31 -0
  88. data/docs/migrations/r8-unit16.md +26 -0
  89. data/docs/migrations/r8-unit17.md +28 -0
  90. data/docs/migrations/r8-unit18.md +29 -0
  91. data/docs/migrations/r8-unit19.md +28 -0
  92. data/docs/migrations/r8-unit20.md +24 -0
  93. data/docs/migrations/r8-unit21.md +28 -0
  94. data/docs/migrations/r8-unit22.md +29 -0
  95. data/docs/migrations/r8-unit23.md +20 -0
  96. data/docs/migrations/r8-unit4.md +67 -0
  97. data/docs/migrations/r8-unit5.md +75 -0
  98. data/docs/migrations/r8-unit6.md +109 -0
  99. data/docs/migrations/r8-unit7.md +31 -0
  100. data/docs/migrations/r8-unit8.md +33 -0
  101. data/docs/migrations/r8-unit9.md +28 -0
  102. data/docs/migrations/storage-async-client.md +103 -0
  103. data/docs/migrations/vector-async-clients.md +110 -0
  104. data/docs/persistence-backends.md +38 -21
  105. data/docs/runtime-and-concurrency.md +26 -1
  106. data/lib/phronomy/agent/admission.rb +78 -0
  107. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  108. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  109. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  110. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  111. data/lib/phronomy/agent/async_event_api.rb +37 -32
  112. data/lib/phronomy/agent/base.rb +74 -72
  113. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  114. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  115. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  116. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  117. data/lib/phronomy/agent/control_request.rb +21 -0
  118. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  119. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  120. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  121. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  122. data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
  123. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  124. data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
  125. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  126. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
  127. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  128. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  129. data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
  130. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  131. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  132. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
  133. data/lib/phronomy/agent/execution_change.rb +161 -0
  134. data/lib/phronomy/agent/execution_environment.rb +36 -0
  135. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  136. data/lib/phronomy/agent/execution_observation.rb +35 -0
  137. data/lib/phronomy/agent/filterable.rb +182 -0
  138. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  139. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  140. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  141. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  142. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  143. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  144. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
  145. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  146. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  147. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  148. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  149. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  150. data/lib/phronomy/agent/persistence/records.rb +33 -0
  151. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  152. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  153. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  154. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  155. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
  156. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
  157. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
  158. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
  159. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  160. data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
  161. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  162. data/lib/phronomy/agent/retention.rb +17 -0
  163. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  164. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  165. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  166. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  167. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  168. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  169. data/lib/phronomy/agent/settings.rb +47 -0
  170. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  171. data/lib/phronomy/agent/store.rb +253 -0
  172. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
  173. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  174. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  175. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  176. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  177. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  178. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  179. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  180. data/lib/phronomy/context/assembly.rb +202 -0
  181. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  182. data/lib/phronomy/context/candidate.rb +51 -0
  183. data/lib/phronomy/context/constraint.rb +47 -0
  184. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  185. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  186. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  187. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  188. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  189. data/lib/phronomy/context/default_policy.rb +140 -0
  190. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  191. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  192. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  193. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  194. data/lib/phronomy/context/manifest_error.rb +10 -0
  195. data/lib/phronomy/context/prompt_template.rb +98 -0
  196. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  197. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  198. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  199. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  200. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  201. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  202. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  203. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  204. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  205. data/lib/phronomy/embeddings/base.rb +43 -0
  206. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  207. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  208. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  209. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  210. data/lib/phronomy/engine/diagnostics.rb +1 -1
  211. data/lib/phronomy/engine/event_loop.rb +7 -7
  212. data/lib/phronomy/engine/execution_binding.rb +23 -0
  213. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  214. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  215. data/lib/phronomy/engine/fsm_session.rb +3 -3
  216. data/lib/phronomy/engine/metrics.rb +16 -14
  217. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  218. data/lib/phronomy/engine/runtime.rb +25 -12
  219. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  220. data/lib/phronomy/execution/async_operation.rb +41 -0
  221. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  222. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  223. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  224. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  225. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  226. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  227. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  228. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  229. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  230. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  231. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  232. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  233. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  234. data/lib/phronomy/execution/runnable.rb +24 -0
  235. data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
  236. data/lib/phronomy/execution/wait_policy.rb +24 -0
  237. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
  238. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  239. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  240. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  241. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  242. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  243. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  244. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  245. data/lib/phronomy/llm_adapter/base.rb +49 -68
  246. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  247. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  248. data/lib/phronomy/llm_adapter/message.rb +62 -0
  249. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  250. data/lib/phronomy/llm_adapter/request.rb +79 -0
  251. data/lib/phronomy/llm_adapter/response.rb +36 -0
  252. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  253. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  254. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  255. data/lib/phronomy/llm_adapter.rb +3 -16
  256. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  257. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  258. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  259. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  260. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  261. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  262. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  263. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  264. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  265. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  266. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  267. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  268. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  269. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  270. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
  271. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  272. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  273. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  274. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  275. data/lib/phronomy/multi_agent/store.rb +156 -0
  276. data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
  277. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  278. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  279. data/lib/phronomy/persistence/content_repository.rb +26 -0
  280. data/lib/phronomy/persistence/errors.rb +16 -0
  281. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  282. data/lib/phronomy/persistence/persistence.rb +23 -0
  283. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  284. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  285. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  286. data/lib/phronomy/persistence/transaction.rb +86 -0
  287. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  288. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  289. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  290. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  291. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  292. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  293. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  294. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  295. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  296. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  297. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  298. data/lib/phronomy/storage/async/async_client.rb +60 -0
  299. data/lib/phronomy/storage/backend.rb +8 -2
  300. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  301. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  302. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  303. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  304. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  305. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  306. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  307. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  308. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  309. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  310. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  311. data/lib/phronomy/tool/authorization.rb +77 -0
  312. data/lib/phronomy/tool/base.rb +549 -9
  313. data/lib/phronomy/tool/call_request.rb +40 -0
  314. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  315. data/lib/phronomy/tool/operation.rb +88 -0
  316. data/lib/phronomy/tool/schema.rb +214 -0
  317. data/lib/phronomy/tool/settings.rb +31 -0
  318. data/lib/phronomy/tool/tool_error.rb +7 -0
  319. data/lib/phronomy/tool/tool_executor.rb +58 -0
  320. data/lib/phronomy/tools/agent.rb +22 -90
  321. data/lib/phronomy/tools/mcp.rb +21 -14
  322. data/lib/phronomy/tools/vector_search.rb +4 -4
  323. data/lib/phronomy/tracing/automatic.rb +11 -6
  324. data/lib/phronomy/tracing/base.rb +1 -1
  325. data/lib/phronomy/tracing/observation.rb +37 -0
  326. data/lib/phronomy/tracing/settings.rb +36 -0
  327. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  328. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  329. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  330. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  331. data/lib/phronomy/vector_store/base.rb +118 -49
  332. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  333. data/lib/phronomy/vector_store.rb +2 -17
  334. data/lib/phronomy/version.rb +1 -1
  335. data/lib/phronomy/workflow/completion.rb +11 -0
  336. data/lib/phronomy/workflow/execution/workflow.rb +7 -7
  337. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  338. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  339. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  340. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
  341. data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
  342. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  343. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  344. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  345. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  346. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  347. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  348. data/lib/phronomy.rb +57 -16
  349. data/scripts/api_snapshot.rb +35 -15
  350. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  351. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  352. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  353. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  354. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  355. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  356. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  357. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  358. data/sig/phronomy/agent/admission.rbs +19 -0
  359. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  360. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  361. data/sig/phronomy/agent/store.rbs +73 -0
  362. data/sig/phronomy/agent.rbs +14 -138
  363. data/sig/phronomy/common.rbs +7 -0
  364. data/sig/phronomy/content_store/contracts.rbs +13 -0
  365. data/sig/phronomy/context.rbs +152 -0
  366. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  367. data/sig/phronomy/embeddings/base.rbs +17 -0
  368. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  369. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  370. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  371. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  372. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  373. data/sig/phronomy/engine/observability.rbs +13 -0
  374. data/sig/phronomy/execution/async_operation.rbs +7 -0
  375. data/sig/phronomy/execution/blocking.rbs +5 -0
  376. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  377. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  378. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  379. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  380. data/sig/phronomy/execution/errors.rbs +7 -0
  381. data/sig/phronomy/execution/execution.rbs +41 -0
  382. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  383. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  384. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  385. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  386. data/sig/phronomy/execution/task_result.rbs +29 -0
  387. data/sig/phronomy/extensions.rbs +0 -21
  388. data/sig/phronomy/handoff.rbs +10 -4
  389. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  390. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  391. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  392. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  393. data/sig/phronomy/llm_context_window.rbs +10 -0
  394. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  395. data/sig/phronomy/multi_agent/store.rbs +54 -0
  396. data/sig/phronomy/multi_agent.rbs +6 -3
  397. data/sig/phronomy/persistence/errors.rbs +18 -0
  398. data/sig/phronomy/persistence/migration.rbs +13 -0
  399. data/sig/phronomy/persistence/transaction.rbs +19 -0
  400. data/sig/phronomy/persistence.rbs +1 -99
  401. data/sig/phronomy/persistence_composition.rbs +19 -0
  402. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  403. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  404. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  405. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
  406. data/sig/phronomy/tool.rbs +48 -4
  407. data/sig/phronomy/tracing/observation.rbs +7 -0
  408. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  409. data/sig/phronomy/vector_store/base.rbs +23 -0
  410. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  411. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  412. data/sig/phronomy/workflow/store.rbs +8 -0
  413. data/sig/phronomy/workflow.rbs +1 -1
  414. data/sig/phronomy.rbs +0 -49
  415. metadata +318 -117
  416. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  417. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  418. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  419. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  420. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  421. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  422. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  423. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  424. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  425. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  426. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  427. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  428. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  429. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  430. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  431. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  432. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  433. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  434. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  435. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  436. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  437. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  438. data/lib/phronomy/configuration/configuration.rb +0 -68
  439. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  440. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  441. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  442. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  443. data/lib/phronomy/engine/runnable.rb +0 -54
  444. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  445. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  446. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  447. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  448. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  449. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  450. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  451. data/lib/phronomy/recovery/recovery.rb +0 -186
  452. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  453. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  454. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  455. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  456. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  457. data/sig/phronomy/execution_receiver.rbs +0 -34
  458. data/sig/phronomy/llm_adapter.rbs +0 -11
  459. data/sig/phronomy/runtime.rbs +0 -76
  460. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  461. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  462. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  463. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  464. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  465. /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
  466. /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
  467. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  468. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  469. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  470. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  471. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  472. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  473. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  474. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  475. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Concurrency
5
- # Represents a bounded execution scope that owns a {CancellationToken} and
6
- # optionally a {Deadline}.
7
- #
8
- # +CancellationScope+ replaces ad-hoc +Timeout.timeout+ calls in agent and
9
- # tool code. All work performed within a scope should observe the scope's
10
- # token; when the scope is cancelled (explicitly or by deadline expiry) the
11
- # token is cancelled and all child tasks that check it will stop.
12
- #
13
- # @example Time-bounded invocation
14
- # scope = Phronomy::Concurrency::CancellationScope.new.deadline_in(30)
15
- # result = scope.pop_queue(completion_queue) do
16
- # raise Phronomy::TimeoutError, "timed out"
17
- # end
18
- #
19
- # @example Explicit cancellation
20
- # scope = Phronomy::Concurrency::CancellationScope.new
21
- # operation = Phronomy::Runtime.instance.offload.submit(
22
- # cancellation_token: scope.token
23
- # ) { synchronous_operation }
24
- # scope.cancel! if some_condition
25
- class CancellationScope
26
- # @return [CancellationToken] the token owned by this scope
27
- attr_reader :token
28
-
29
- # @return [Deadline, nil] the deadline attached to this scope, if any
30
- attr_reader :deadline
31
-
32
- # @param parent_token [CancellationToken, nil] when provided, cancellation of
33
- # the parent token is propagated to this scope's token via a callback
34
- # (for explicit cancel) and/or the Runtime timer queue (for monotonic
35
- # deadline expiry). No polling thread is spawned.
36
- # @api private
37
- def initialize(parent_token: nil)
38
- @token = Phronomy::Concurrency::CancellationToken.new
39
- @deadline = nil
40
-
41
- if parent_token
42
- # Propagate explicit cancel() from parent to child via callback.
43
- parent_token.on_cancel { @token.cancel! }
44
-
45
- # Propagate monotonic-deadline expiry from parent to child via the
46
- # timer queue (avoids a polling thread).
47
- remaining = parent_token.remaining_monotonic_seconds
48
- if !remaining.nil?
49
- if remaining <= 0
50
- @token.cancel!
51
- else
52
- Phronomy::Runtime.instance.timer_queue.schedule(seconds: remaining) do
53
- @token.cancel!
54
- end
55
- end
56
- end
57
- end
58
- end
59
-
60
- # Attaches a deadline that will cancel this scope after +seconds+.
61
- #
62
- # @param seconds [Numeric] timeout duration
63
- # @return [self]
64
- # @api private
65
- def deadline_in(seconds)
66
- @deadline = Phronomy::Concurrency::Deadline.in(seconds)
67
- @deadline.attach_to(@token)
68
- self
69
- end
70
-
71
- # Cancels this scope immediately.
72
- # @return [void]
73
- # @api private
74
- def cancel!
75
- @token.cancel!
76
- end
77
-
78
- # Returns +true+ if this scope has been cancelled.
79
- # @return [Boolean]
80
- # @api private
81
- def cancelled?
82
- @token.cancelled?
83
- end
84
-
85
- # Returns the remaining time in seconds before the deadline expires,
86
- # or +nil+ when no deadline is set.
87
- # @return [Float, nil]
88
- # @api private
89
- def remaining_seconds
90
- @deadline&.remaining_seconds
91
- end
92
-
93
- # Pops from +queue+ with a timeout derived from the attached deadline (or
94
- # +fallback_timeout+ seconds when no deadline is set). If the pop times out,
95
- # the scope is cancelled and the block is called (or a {TimeoutError} raised).
96
- #
97
- # @param queue [Phronomy::Concurrency::AsyncQueue] the queue to pop from
98
- # @param fallback_timeout [Numeric, nil] used when no deadline is attached
99
- # @yield called when the operation times out
100
- # @raise [Phronomy::TimeoutError] when no block is given and a timeout occurs
101
- # @return [Object] the popped value
102
- # @api private
103
- def pop_queue(queue, fallback_timeout: nil)
104
- timeout = @deadline&.remaining_seconds || fallback_timeout
105
- result = if timeout
106
- queue.pop(timeout: timeout)
107
- else
108
- queue.pop
109
- end
110
-
111
- if result.nil?
112
- cancel!
113
- if block_given?
114
- yield
115
- else
116
- raise Phronomy::TimeoutError, "CancellationScope timed out"
117
- end
118
- end
119
-
120
- result
121
- end
122
- end
123
- end
124
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Concurrency
5
- # Connects explicit invocation controls before operation admission. Its token
6
- # is private: cancelling it never cancels the application's shared tokens.
7
- # Used by Agent, Blocking and Orchestrator admission; it owns no worker.
8
- # @api private
9
- class OperationBinding
10
- attr_reader :token, :scope
11
-
12
- def initialize(invocation_context:, cancellation_token:)
13
- if !invocation_context.nil? && !invocation_context.is_a?(InvocationContext)
14
- raise TypeError, "invocation_context must be a Phronomy::InvocationContext or nil"
15
- end
16
- @scope = invocation_context&.__execution_scope
17
- @token = CancellationToken.new
18
- @subscriptions = Subscriptions.new
19
- [invocation_context&.cancellation_token, cancellation_token].compact.uniq.each do |source|
20
- @subscriptions.cancellation(source) { @token.cancel! }
21
- end
22
- if !@scope && invocation_context&.deadline
23
- @subscriptions.after(invocation_context.deadline.remaining_seconds) { @token.cancel! }
24
- end
25
- @token.cancel! if @scope && !@scope.__open?
26
- end
27
-
28
- def bind(result)
29
- result.__bind_execution(@scope)
30
- track(result)
31
- end
32
-
33
- def track(result)
34
- @subscriptions.result(result) { @subscriptions.close }
35
- result
36
- end
37
-
38
- def close
39
- @subscriptions.close
40
- end
41
- end
42
- end
43
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Internal lifecycle/delivery contract for feature-owned execution state.
5
- # Receivers are retained by one EventLoop, not an application callback SPI.
6
- # Normal mutation and delivery run only on that loop. idle? runs with its
7
- # lifecycle lock held; it must not call Runtime or acquire that lock again.
8
- # shutdown runs on a failing loop, or exclusively after a clean loop joins.
9
- # @api private
10
- class ExecutionReceiver
11
- def self.for(event_loop)
12
- event_loop.__execution_receiver(key: self) ||
13
- event_loop.__register_execution_receiver(key: self, receiver: new(event_loop: event_loop))
14
- end
15
-
16
- # Lookup only: neither a loop nor a receiver is created during inspection.
17
- def self.existing_for(runtime)
18
- runtime.__event_loop_if_initialized&.__execution_receiver(key: self)
19
- end
20
-
21
- def initialize(event_loop:)
22
- @event_loop = event_loop
23
- end
24
-
25
- def __bound_to?(event_loop)
26
- @event_loop.equal?(event_loop)
27
- end
28
-
29
- def idle?
30
- raise NotImplementedError
31
- end
32
-
33
- def deliver(message)
34
- raise NotImplementedError
35
- end
36
-
37
- def shutdown(error:)
38
- raise NotImplementedError
39
- end
40
-
41
- def session_retired(fsm_session_id, reason:)
42
- end
43
-
44
- private
45
-
46
- def synchronize(&block)
47
- @event_loop.__synchronize_execution_state(&block)
48
- end
49
-
50
- def admit(&block)
51
- @event_loop.__admit_execution(self, &block)
52
- end
53
-
54
- def post_message(message, admission: false, completion: nil)
55
- @event_loop.__post_execution(self, message, admission: admission, completion: completion)
56
- end
57
-
58
- def assert_event_loop_thread!
59
- return if @event_loop.current?
60
-
61
- raise Phronomy::Error,
62
- "Phronomy-managed live execution state may only be mutated on EventLoop"
63
- end
64
- end
65
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Base interface for executable graph components.
5
- # Provides invoke / stream / batch.
6
- module Runnable
7
- # Synchronous execution. Must be overridden in subclasses.
8
- def invoke(input, config: {})
9
- raise NotImplementedError, "#{self.class}#invoke is not implemented"
10
- end
11
-
12
- # Streaming execution. Default yields the invoke result as a single chunk.
13
- def stream(input, config: {}, &block)
14
- result = invoke(input, config: config)
15
- yield result if block
16
- result
17
- end
18
-
19
- # Batch execution. Default calls invoke sequentially.
20
- def batch(inputs, config: {})
21
- inputs.map { |input| invoke(input, config: config) }
22
- end
23
-
24
- # Convenience wrapper that delegates to the global tracer.
25
- # Yields a span; the block must return [result, usage] where usage is a
26
- # Phronomy::TokenUsage or nil. Returns only the result value.
27
- #
28
- # When +trace_pii+ is disabled, both the input and the output (LLM response,
29
- # tool result) are replaced with the literal string "[REDACTED]" before being
30
- # forwarded to the tracing backend. The actual result is still returned to
31
- # the caller — only the copy sent to the tracer is redacted.
32
- #
33
- # @example
34
- # trace("my_chain", input: input) { [invoke(input), nil] }
35
- # @api public
36
- def trace(name, input: nil, **meta, &block)
37
- traced_input = Phronomy.configuration.trace_pii ? input : "[REDACTED]"
38
-
39
- if Phronomy.configuration.trace_pii
40
- # PII recording is allowed: pass through unchanged.
41
- Phronomy.configuration.tracer.trace(name, input: traced_input, **meta, &block)
42
- else
43
- # Redact both input (above) and output before forwarding to the tracer.
44
- # Capture the real result so callers receive the unredacted value.
45
- real_result = nil
46
- Phronomy.configuration.tracer.trace(name, input: traced_input, **meta) do |span|
47
- real_result, usage = block.call(span)
48
- ["[REDACTED]", usage]
49
- end
50
- real_result
51
- end
52
- end
53
- end
54
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module LLMAdapter
5
- # Default LLMAdapter SPI implementation backed by RubyLLM.
6
- #
7
- # The synchronous +chat.ask+ / +chat.complete+ calls are invoked through the
8
- # framework-owned async bridge in {LLMAdapter::Base}, so adapter consumers do
9
- # not need to manage OffloadPool themselves.
10
- #
11
- # @example Explicitly configuring this adapter
12
- # Phronomy.configure do |c|
13
- # c.llm_adapter = Phronomy::LLMAdapter::RubyLLM.new
14
- # end
15
- #
16
- # @api public
17
- class RubyLLM < Base
18
- # Delegates to +chat.ask(message)+ or +chat.complete+ when message is nil.
19
- #
20
- # Passing +nil+ for +message+ is used by the ReAct loop for continuation
21
- # turns where the user message has already been added to the chat history
22
- # (for example after a Tool result).
23
- #
24
- # @param chat [Object] RubyLLM chat session
25
- # @param message [String, nil] user message, or nil to continue the chat
26
- # @param config [Hash] invocation config (not used directly here)
27
- # @return [Object] RubyLLM response
28
- # @api public
29
- def complete(chat, message, config: {})
30
- message ? chat.ask(message) : chat.complete
31
- end
32
-
33
- # Delegates to +chat.ask(message) { |chunk| ... }+ or +chat.complete(&block)+
34
- # when message is nil.
35
- #
36
- # @param chat [Object] RubyLLM chat session
37
- # @param message [String, nil] user message, or nil to continue the chat
38
- # @param config [Hash] invocation config
39
- # @yield [chunk] streaming chunk forwarded from RubyLLM
40
- # @return [Object] RubyLLM response
41
- # @api public
42
- def stream(chat, message, config: {}, &block)
43
- message ? chat.ask(message, &block) : chat.complete(&block)
44
- end
45
- end
46
- end
47
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Immutable value object that holds token usage counts for a single LLM call
5
- # or an accumulated total across multiple calls.
6
- #
7
- # Fields mirror the values reported by RubyLLM::Tokens:
8
- #
9
- # input - tokens consumed by the input (prompt)
10
- # output - tokens produced by the model (completion)
11
- # cached - input tokens served from the provider's prompt cache
12
- # cache_creation - input tokens written into the prompt cache (Anthropic)
13
- #
14
- # All fields are Integer or nil (nil means the provider did not report that
15
- # value for this call).
16
- #
17
- # @example Accumulate usage across a ReAct loop
18
- # total = Phronomy::TokenUsage.zero
19
- # chat.messages.each do |msg|
20
- # total += Phronomy::TokenUsage.from_tokens(msg.tokens)
21
- # end
22
- class TokenUsage
23
- attr_reader :input, :output, :cached, :cache_creation
24
-
25
- def initialize(input: nil, output: nil, cached: nil, cache_creation: nil)
26
- @input = input
27
- @output = output
28
- @cached = cached
29
- @cache_creation = cache_creation
30
- end
31
-
32
- # Returns a zero-valued TokenUsage suitable as an accumulator seed.
33
- def self.zero
34
- new(input: 0, output: 0, cached: 0, cache_creation: 0)
35
- end
36
-
37
- # Builds a TokenUsage from a RubyLLM::Tokens object. Returns zero
38
- # when tokens is nil (provider did not report usage).
39
- # nil fields within the tokens object are coerced to 0.
40
- def self.from_tokens(tokens)
41
- return zero if tokens.nil?
42
-
43
- new(
44
- input: tokens.input || 0,
45
- output: tokens.output || 0,
46
- cached: tokens.cache_read || 0,
47
- cache_creation: tokens.cache_write || 0
48
- )
49
- end
50
-
51
- # Adds two TokenUsage instances. nil fields are treated as 0 so that
52
- # partially-reported usage accumulates correctly.
53
- # When other is nil, returns self unchanged.
54
- def +(other)
55
- return self if other.nil?
56
-
57
- self.class.new(
58
- input: _add(input, other.input),
59
- output: _add(output, other.output),
60
- cached: _add(cached, other.cached),
61
- cache_creation: _add(cache_creation, other.cache_creation)
62
- )
63
- end
64
-
65
- def ==(other)
66
- other.is_a?(TokenUsage) &&
67
- input == other.input &&
68
- output == other.output &&
69
- cached == other.cached &&
70
- cache_creation == other.cache_creation
71
- end
72
-
73
- def to_h
74
- {input: input, output: output, cached: cached, cache_creation: cache_creation}
75
- end
76
-
77
- private
78
-
79
- def _add(a, b)
80
- return nil if a.nil? && b.nil?
81
-
82
- (a || 0) + (b || 0)
83
- end
84
- end
85
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module MultiAgent
5
- module Persistence
6
- # Read and assemble domain results; the public entry point owns the execution-thread guard.
7
- # @api private
8
- class Queries
9
- def initialize(repositories)
10
- @repositories = repositories
11
- end
12
-
13
- def team_execution_result(team_execution_id)
14
- execution = @repositories.team_executions.load(team_execution_id)
15
- {
16
- team_execution_id: execution.team_execution_id, team_id: execution.team_id,
17
- status: execution.status, phase: execution.phase,
18
- result_ref: execution.result_ref, error_ref: execution.error_ref,
19
- result: execution.result_ref && @repositories.contents.fetch_json(execution.result_ref),
20
- error: execution.error_ref && @repositories.contents.fetch_json(execution.error_ref)
21
- }.then { |value| Phronomy::Values::Immutable.copy(value) }
22
- end
23
-
24
- def list_team_executions(team_id, after: nil, limit: 100)
25
- @repositories.team_executions.list(team_id, after: after, limit: limit)
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- # Domain-owned Team metadata, independent of coordination runtime loading.
5
- # @api private
6
- module TeamStorageSchema
7
- ROOTS = Phronomy::Storage::Resource.new(id: "team.roots", kind: :records,
8
- guard: {resource: "team.roots", via: :key})
9
- EXECUTIONS = Phronomy::Storage::Resource.new(id: "team.executions", kind: :records,
10
- attributes: {owner: :string, active: :boolean}, immutable_attributes: [:owner],
11
- indexes: {owner: [:owner], owner_active: [:owner, :active]},
12
- unique: [{name: :one_active_owner, fields: [:owner], where: {active: true}}],
13
- guard: {resource: ROOTS.id, via: :owner})
14
- end
15
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../common/error"
4
-
5
- module Phronomy
6
- class ParseError < Error; end
7
- end
@@ -1,140 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- class Persistence
5
- # Content-addressed immutable content repository. ContentStore has its own
6
- # codec/canonicalization boundary and is not wrapped in DurableRecord.
7
- #
8
- # @return [Object]
9
- # @api public
10
- def contents = @repositories.contents
11
-
12
- # Runtime/domain-facing AgentRoot repository. The injected backend is
13
- # record-oriented; this facade owns encode/decode.
14
- #
15
- # @return [Object]
16
- # @api public
17
- def agents = @repositories.agents
18
-
19
- # Runtime/domain-facing append-only Agent Journal repository.
20
- #
21
- # @return [Object]
22
- # @api public
23
- def journals = @repositories.journals
24
-
25
- # Runtime/domain-facing AgentExecution repository.
26
- #
27
- # @return [Object]
28
- # @api public
29
- def executions = @repositories.executions
30
-
31
- # Runtime/domain-facing durable Workflow snapshot repository.
32
- #
33
- # @return [Object]
34
- # @api public
35
- def workflow_states = @repositories.workflow_states
36
-
37
- # Purpose-specific durable Handoff and Team repositories in atomic_all.
38
- # @api public
39
- def handoff_states = @repositories.handoff_states
40
-
41
- # @api public
42
- def teams = @repositories.teams
43
-
44
- # @api public
45
- def team_executions = @repositories.team_executions
46
-
47
- # Read-only exact Agent execution result; never creates a live Agent owner.
48
- # Result is nil until a result_ref exists; errors remain canonical data.
49
- # @api public
50
- def execution_result(execution_id)
51
- assert_observation_thread!
52
- Phronomy::Agent::Persistence::Queries.new(self).execution_result(execution_id)
53
- end
54
-
55
- # Follows one exact Handoff turn without constructing a live Agent or graph.
56
- # A committed absent Target reservation remains active; failed reads raise.
57
- # @api public
58
- def handoff_result(execution_id, main_agent_id: nil)
59
- assert_observation_thread!
60
- Phronomy::Agent::Persistence::Queries.new(self).handoff_result(execution_id, main_agent_id: main_agent_id)
61
- end
62
-
63
- # Lists retained active and terminal executions in lexical ID order.
64
- # after is an exclusive ID cursor; discovery does not imply request dedup.
65
- # @api public
66
- def list_executions(agent_id, after: nil, limit: 100)
67
- assert_observation_thread!
68
- Phronomy::Agent::Persistence::Queries.new(self).list_executions(agent_id, after: after, limit: limit)
69
- end
70
-
71
- # Read-only exact Team result, independent of current Team class/Proc wiring.
72
- # @api public
73
- def team_execution_result(team_execution_id)
74
- assert_observation_thread!
75
- Phronomy::MultiAgent::Persistence::Queries.new(self).team_execution_result(team_execution_id)
76
- end
77
-
78
- # Lists retained Team runs; no continuation or callback delivery occurs.
79
- # @api public
80
- def list_team_executions(team_id, after: nil, limit: 100)
81
- assert_observation_thread!
82
- Phronomy::MultiAgent::Persistence::Queries.new(self).list_team_executions(team_id, after: after, limit: limit)
83
- end
84
-
85
- # The selected raw storage backend, for backend-specific administration.
86
- # Read and write domain records through the repository accessors above.
87
- # @api public
88
- attr_reader :backend
89
-
90
- # Assembles domain repositories over one synchronous storage backend.
91
- # @api public
92
- def initialize(backend:)
93
- Phronomy::Storage::Backend.validate_capabilities!(backend)
94
- PersistenceComposition::StorageSchema.validate!(backend.view)
95
- @backend = backend
96
- @repositories = PersistenceComposition::Repositories.new(backend.view)
97
- end
98
-
99
- # Constructs an isolated in-memory storage domain with standard codecs.
100
- # @api public
101
- def self.in_memory
102
- new(backend: Phronomy::Storage::Backends::InMemory.new(resources: PersistenceComposition::StorageSchema.resources))
103
- end
104
-
105
- # @api public
106
- def capabilities = {atomic_all: true, atomic_admission: true, optimistic_revision: true}.freeze
107
-
108
- # Executes a single backend transaction and exposes domain repositories
109
- # bound to its raw view. Codec and caller failures remain inside the backend
110
- # block so the backend can roll them back. The block result is returned.
111
- # Explicit nested calls on this service use savepoint semantics: a failed
112
- # inner scope rolls back and re-raises; a successful inner scope is committed
113
- # only with its outer scope. See Storage::Backend#transaction.
114
- # Storage failures whose commit outcome is fundamentally
115
- # unknown remain backend/database failures; Phronomy does not claim
116
- # exactly-once semantics for such failures.
117
- # @api public
118
- def transaction
119
- backend.transaction do |raw_view|
120
- repositories = PersistenceComposition::Repositories.new(raw_view)
121
- yield repositories
122
- end
123
- end
124
-
125
- # @api public
126
- def assert_agent_watermark!(agent_id:, agent_revision:, journal_position:)
127
- @repositories.assert_agent_watermark!(
128
- agent_id: agent_id, agent_revision: agent_revision, journal_position: journal_position
129
- )
130
- end
131
-
132
- private
133
-
134
- def assert_observation_thread!
135
- if Phronomy::Runtime.in_event_loop_context?
136
- raise Phronomy::EventLoopReentrancyError, "Persistence observation cannot block EventLoop"
137
- end
138
- end
139
- end
140
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module PersistenceComposition
5
- # Assemble domain repositories over one raw backend or transaction view.
6
- # @api private
7
- class Repositories
8
- attr_reader :contents
9
-
10
- def initialize(view)
11
- @view = view
12
- @contents = Phronomy::ContentStore::StoredContents.new(view)
13
- @domain_repositories = {}
14
- @repository_lock = Mutex.new
15
- end
16
-
17
- def agents
18
- domain_repository(:agents) do
19
- Phronomy::Agent::Persistence::AgentRepository.new(@view)
20
- end
21
- end
22
-
23
- def journals
24
- domain_repository(:journals) do
25
- Phronomy::Agent::Persistence::JournalRepository.new(@view)
26
- end
27
- end
28
-
29
- def executions
30
- domain_repository(:executions) do
31
- Phronomy::Agent::Persistence::ExecutionRepository.new(@view)
32
- end
33
- end
34
-
35
- def workflow_states
36
- domain_repository(:workflow_states) do
37
- Phronomy::Workflow::Persistence::StateRepository.new(@view)
38
- end
39
- end
40
-
41
- def handoff_states
42
- domain_repository(:handoff_states) do
43
- Phronomy::Agent::Persistence::HandoffStateRepository.new(@view)
44
- end
45
- end
46
-
47
- def teams
48
- domain_repository(:teams) do
49
- Phronomy::MultiAgent::Persistence::TeamRepository.new(@view)
50
- end
51
- end
52
-
53
- def team_executions
54
- domain_repository(:team_executions) do
55
- Phronomy::MultiAgent::Persistence::TeamExecutionRepository.new(@view)
56
- end
57
- end
58
-
59
- def assert_agent_watermark!(agent_id:, agent_revision:, journal_position:)
60
- Phronomy::Agent::Persistence::Watermark.new(@view).check!(
61
- agent_id: agent_id.to_s,
62
- agent_revision: Integer(agent_revision),
63
- journal_position: Integer(journal_position)
64
- )
65
- end
66
-
67
- private
68
-
69
- # Cache one wrapper per view without loading unused domain implementations.
70
- def domain_repository(name)
71
- @repository_lock.synchronize do
72
- @domain_repositories.fetch(name) { @domain_repositories[name] = yield }
73
- end
74
- end
75
- end
76
- end
77
- end