phronomy 0.26.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 (557) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +92 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +13 -3
  6. data/VERIFY.sh +27 -27
  7. data/benchmark/bench_agent_invoke.rb +26 -47
  8. data/benchmark/bench_context_assembler.rb +17 -15
  9. data/benchmark/bench_regression.rb +1 -1
  10. data/benchmark/bench_tool_schema.rb +1 -1
  11. data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
  12. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  13. data/docs/architecture/agent-context.md +4 -2
  14. data/docs/architecture/agent-transition-ownership.md +13 -0
  15. data/docs/architecture/backend-groups.md +152 -0
  16. data/docs/architecture/before-llm-input.md +9 -3
  17. data/docs/architecture/context-management.md +31 -1
  18. data/docs/architecture/context-preparation-steps.md +90 -0
  19. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  20. data/docs/architecture/execution-abstraction-review.md +88 -0
  21. data/docs/architecture/execution-boundaries.md +28 -0
  22. data/docs/architecture/execution-metadata-and-values.md +86 -0
  23. data/docs/architecture/generator-verifier-ownership.md +111 -0
  24. data/docs/architecture/multi-agent-handoff.md +11 -4
  25. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  26. data/docs/architecture/persistence.md +45 -4
  27. data/docs/architecture/r8-unit1.md +104 -0
  28. data/docs/architecture/r8-unit10.md +72 -0
  29. data/docs/architecture/r8-unit11.md +71 -0
  30. data/docs/architecture/r8-unit12.md +67 -0
  31. data/docs/architecture/r8-unit13.md +61 -0
  32. data/docs/architecture/r8-unit14.md +72 -0
  33. data/docs/architecture/r8-unit15.md +65 -0
  34. data/docs/architecture/r8-unit16.md +54 -0
  35. data/docs/architecture/r8-unit17.md +73 -0
  36. data/docs/architecture/r8-unit18.md +92 -0
  37. data/docs/architecture/r8-unit19.md +61 -0
  38. data/docs/architecture/r8-unit2.md +55 -0
  39. data/docs/architecture/r8-unit20.md +51 -0
  40. data/docs/architecture/r8-unit21.md +79 -0
  41. data/docs/architecture/r8-unit22.md +74 -0
  42. data/docs/architecture/r8-unit23.md +81 -0
  43. data/docs/architecture/r8-unit3.md +130 -0
  44. data/docs/architecture/r8-unit4.md +79 -0
  45. data/docs/architecture/r8-unit5.md +115 -0
  46. data/docs/architecture/r8-unit6.md +71 -0
  47. data/docs/architecture/r8-unit7.md +70 -0
  48. data/docs/architecture/r8-unit8.md +78 -0
  49. data/docs/architecture/r8-unit9.md +73 -0
  50. data/docs/architecture/refactoring-closure.md +343 -0
  51. data/docs/architecture/remaining-refactoring-plan.md +390 -0
  52. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  53. data/docs/architecture/storage-execution-boundaries.md +54 -0
  54. data/docs/architecture/tool-schema-recording-gap.md +56 -0
  55. data/docs/architecture/tracing.md +2 -2
  56. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  57. data/docs/architecture.md +222 -0
  58. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  59. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  60. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  61. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  62. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  63. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  64. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
  65. data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
  66. data/docs/decisions/032-storage-backend-composition.md +85 -0
  67. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  68. data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
  69. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  70. data/docs/decisions/036-context-contract-ownership.md +86 -0
  71. data/docs/decisions/037-common-definition-ownership.md +62 -0
  72. data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
  73. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
  74. data/docs/decisions/040-configuration-default-composition.md +105 -0
  75. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  76. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  77. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  78. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  79. data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
  80. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  81. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  82. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  83. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  84. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  85. data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
  86. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  87. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  88. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  89. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  90. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  91. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  92. data/docs/decisions/058-neutral-storage-primitives.md +83 -0
  93. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  94. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  95. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  96. data/docs/decisions/062-content-store-service.md +52 -0
  97. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  98. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  99. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  100. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  101. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  102. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  103. data/docs/decisions/README.md +52 -6
  104. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  105. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  106. data/docs/execution-boundaries-preview.md +45 -0
  107. data/docs/features.md +16 -5
  108. data/docs/getting-started.md +11 -8
  109. data/docs/migrations/0.15.md +5 -0
  110. data/docs/migrations/0.22.md +2 -2
  111. data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
  112. data/docs/migrations/handoff-runner-multi-agent.md +37 -0
  113. data/docs/migrations/neutral-storage-spi.md +43 -0
  114. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  115. data/docs/migrations/persistence-failure-contracts.md +67 -0
  116. data/docs/migrations/r8-unit10.md +36 -0
  117. data/docs/migrations/r8-unit11.md +33 -0
  118. data/docs/migrations/r8-unit12.md +31 -0
  119. data/docs/migrations/r8-unit13.md +36 -0
  120. data/docs/migrations/r8-unit14.md +31 -0
  121. data/docs/migrations/r8-unit15.md +31 -0
  122. data/docs/migrations/r8-unit16.md +26 -0
  123. data/docs/migrations/r8-unit17.md +28 -0
  124. data/docs/migrations/r8-unit18.md +29 -0
  125. data/docs/migrations/r8-unit19.md +28 -0
  126. data/docs/migrations/r8-unit20.md +24 -0
  127. data/docs/migrations/r8-unit21.md +28 -0
  128. data/docs/migrations/r8-unit22.md +29 -0
  129. data/docs/migrations/r8-unit23.md +20 -0
  130. data/docs/migrations/r8-unit4.md +67 -0
  131. data/docs/migrations/r8-unit5.md +75 -0
  132. data/docs/migrations/r8-unit6.md +109 -0
  133. data/docs/migrations/r8-unit7.md +31 -0
  134. data/docs/migrations/r8-unit8.md +33 -0
  135. data/docs/migrations/r8-unit9.md +28 -0
  136. data/docs/migrations/shared-state-multi-agent.md +44 -0
  137. data/docs/migrations/storage-async-client.md +103 -0
  138. data/docs/migrations/storage-backend-composition.md +117 -0
  139. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  140. data/docs/migrations/vector-async-clients.md +110 -0
  141. data/docs/persistence-backends.md +190 -215
  142. data/docs/runtime-and-concurrency.md +142 -32
  143. data/lib/phronomy/agent/admission.rb +78 -0
  144. data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
  145. data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
  146. data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
  147. data/lib/phronomy/agent/api/agent.rb +17 -0
  148. data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
  149. data/lib/phronomy/agent/async_event_api.rb +38 -33
  150. data/lib/phronomy/agent/base.rb +106 -294
  151. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  152. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  153. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  154. data/lib/phronomy/agent/context_importer.rb +2 -2
  155. data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
  156. data/lib/phronomy/agent/control_request.rb +21 -0
  157. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  158. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
  159. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  160. data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
  161. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
  162. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
  163. data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
  164. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  165. data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
  166. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
  167. data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
  168. data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
  169. data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
  170. data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
  171. data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
  172. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  173. data/lib/phronomy/agent/execution_change.rb +161 -0
  174. data/lib/phronomy/agent/execution_environment.rb +36 -0
  175. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  176. data/lib/phronomy/agent/execution_observation.rb +35 -0
  177. data/lib/phronomy/agent/filterable.rb +182 -0
  178. data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
  179. data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
  180. data/lib/phronomy/agent/handoff_error.rb +7 -0
  181. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  182. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  183. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  184. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  185. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  186. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  187. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
  188. data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
  189. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  190. data/lib/phronomy/agent/persistence/codec.rb +338 -0
  191. data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
  192. data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
  193. data/lib/phronomy/agent/persistence/records.rb +33 -0
  194. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  195. data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
  196. data/lib/phronomy/agent/persistence/watermark.rb +29 -0
  197. data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
  198. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
  199. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
  200. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
  201. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
  202. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  203. data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
  204. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  205. data/lib/phronomy/agent/retention.rb +17 -0
  206. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  207. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  208. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  209. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  210. data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
  211. data/lib/phronomy/agent/saved_context_reader.rb +55 -0
  212. data/lib/phronomy/agent/settings.rb +47 -0
  213. data/lib/phronomy/agent/state_writer.rb +166 -0
  214. data/lib/phronomy/agent/store.rb +253 -0
  215. data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
  216. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  217. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  218. data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
  219. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
  220. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  221. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  222. data/lib/phronomy/common/configuration_error.rb +7 -0
  223. data/lib/phronomy/common/error.rb +5 -0
  224. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  225. data/lib/phronomy/common/values/serializable.rb +32 -0
  226. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  227. data/lib/phronomy/content_store/storage_schema.rb +12 -0
  228. data/lib/phronomy/content_store/stored_contents.rb +44 -0
  229. data/lib/phronomy/context/assembly.rb +202 -0
  230. data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
  231. data/lib/phronomy/context/candidate.rb +51 -0
  232. data/lib/phronomy/context/constraint.rb +47 -0
  233. data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
  234. data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
  235. data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
  236. data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
  237. data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
  238. data/lib/phronomy/context/default_policy.rb +140 -0
  239. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  240. data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
  241. data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
  242. data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
  243. data/lib/phronomy/context/manifest_error.rb +10 -0
  244. data/lib/phronomy/context/prompt_template.rb +98 -0
  245. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  246. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  247. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  248. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  249. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  250. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  251. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  252. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  253. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  254. data/lib/phronomy/embeddings/base.rb +43 -0
  255. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  256. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  257. data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
  258. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  259. data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
  260. data/lib/phronomy/engine/event_loop.rb +164 -630
  261. data/lib/phronomy/engine/execution_binding.rb +23 -0
  262. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  263. data/lib/phronomy/engine/fsm_protocol.rb +9 -0
  264. data/lib/phronomy/engine/fsm_session.rb +37 -30
  265. data/lib/phronomy/engine/metrics.rb +28 -0
  266. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  267. data/lib/phronomy/engine/runtime.rb +104 -95
  268. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  269. data/lib/phronomy/execution/async_operation.rb +41 -0
  270. data/lib/phronomy/execution/backpressure_error.rb +7 -0
  271. data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
  272. data/lib/phronomy/execution/cancellation_error.rb +7 -0
  273. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
  274. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  275. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  276. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  277. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  278. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  279. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  280. data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
  281. data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
  282. data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
  283. data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
  284. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  285. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  286. data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
  287. data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
  288. data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
  289. data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
  290. data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
  291. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  292. data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
  293. data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
  294. data/lib/phronomy/execution/runnable.rb +24 -0
  295. data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
  296. data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
  297. data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
  298. data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
  299. data/lib/phronomy/execution/timeout_error.rb +7 -0
  300. data/lib/phronomy/execution/wait_policy.rb +24 -0
  301. data/lib/phronomy/filter/filter_block_error.rb +14 -0
  302. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  303. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  304. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  305. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  306. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  307. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  308. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  309. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  310. data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
  311. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  312. data/lib/phronomy/llm_adapter/base.rb +49 -68
  313. data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
  314. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  315. data/lib/phronomy/llm_adapter/message.rb +62 -0
  316. data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
  317. data/lib/phronomy/llm_adapter/request.rb +79 -0
  318. data/lib/phronomy/llm_adapter/response.rb +36 -0
  319. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  320. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  321. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  322. data/lib/phronomy/llm_adapter.rb +3 -16
  323. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  324. data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
  325. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  326. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  327. data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
  328. data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
  329. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  330. data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
  331. data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
  332. data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
  333. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  334. data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
  335. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  336. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  337. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  338. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
  339. data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
  340. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  341. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  342. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  343. data/lib/phronomy/multi_agent/store.rb +156 -0
  344. data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
  345. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  346. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
  347. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  348. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  349. data/lib/phronomy/persistence/content_repository.rb +26 -0
  350. data/lib/phronomy/persistence/errors.rb +16 -0
  351. data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
  352. data/lib/phronomy/persistence/persistence.rb +23 -0
  353. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  354. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  355. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  356. data/lib/phronomy/persistence/transaction.rb +86 -0
  357. data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
  358. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  359. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  360. data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
  361. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  362. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  363. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  364. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  365. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  366. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  367. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  368. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  369. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  370. data/lib/phronomy/storage/async/async_client.rb +60 -0
  371. data/lib/phronomy/storage/backend.rb +107 -0
  372. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  373. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  374. data/lib/phronomy/storage/blobs.rb +31 -0
  375. data/lib/phronomy/storage/condition.rb +25 -0
  376. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  377. data/lib/phronomy/storage/conflict_error.rb +9 -0
  378. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  379. data/lib/phronomy/storage/entry.rb +33 -0
  380. data/lib/phronomy/storage/guard_ref.rb +13 -0
  381. data/lib/phronomy/storage/not_found_error.rb +9 -0
  382. data/lib/phronomy/storage/record_codec.rb +177 -0
  383. data/lib/phronomy/storage/records.rb +61 -0
  384. data/lib/phronomy/storage/resource.rb +126 -0
  385. data/lib/phronomy/storage/scope.rb +25 -0
  386. data/lib/phronomy/storage/serialization_error.rb +9 -0
  387. data/lib/phronomy/storage/streams.rb +44 -0
  388. data/lib/phronomy/storage/transaction_error.rb +10 -0
  389. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  390. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  391. data/lib/phronomy/storage/validation.rb +53 -0
  392. data/lib/phronomy/storage/view.rb +131 -0
  393. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  394. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  395. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  396. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  397. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
  398. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
  399. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
  400. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  401. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
  402. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  403. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
  404. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  405. data/lib/phronomy/tool/authorization.rb +77 -0
  406. data/lib/phronomy/tool/base.rb +549 -9
  407. data/lib/phronomy/tool/call_request.rb +40 -0
  408. data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
  409. data/lib/phronomy/tool/operation.rb +88 -0
  410. data/lib/phronomy/tool/schema.rb +214 -0
  411. data/lib/phronomy/tool/settings.rb +31 -0
  412. data/lib/phronomy/tool/tool_error.rb +7 -0
  413. data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
  414. data/lib/phronomy/tools/agent.rb +22 -90
  415. data/lib/phronomy/tools/mcp.rb +21 -14
  416. data/lib/phronomy/tools/vector_search.rb +4 -4
  417. data/lib/phronomy/tracing/automatic.rb +11 -6
  418. data/lib/phronomy/tracing/base.rb +1 -1
  419. data/lib/phronomy/tracing/observation.rb +37 -0
  420. data/lib/phronomy/tracing/settings.rb +36 -0
  421. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  422. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  423. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  424. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  425. data/lib/phronomy/vector_store/base.rb +118 -49
  426. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  427. data/lib/phronomy/vector_store.rb +2 -17
  428. data/lib/phronomy/version.rb +1 -1
  429. data/lib/phronomy/workflow/completion.rb +11 -0
  430. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  431. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  432. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
  433. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  434. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  435. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
  436. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
  437. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  438. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  439. data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
  440. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  441. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  442. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  443. data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
  444. data/lib/phronomy.rb +97 -98
  445. data/scripts/api_snapshot.rb +36 -16
  446. data/scripts/storage_spi_snapshot.rb +36 -0
  447. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  448. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  449. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  450. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  451. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  452. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  453. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  454. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  455. data/sig/phronomy/agent/admission.rbs +19 -0
  456. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  457. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  458. data/sig/phronomy/agent/store.rbs +73 -0
  459. data/sig/phronomy/agent.rbs +14 -139
  460. data/sig/phronomy/common.rbs +7 -0
  461. data/sig/phronomy/content_store/contracts.rbs +13 -0
  462. data/sig/phronomy/context.rbs +152 -0
  463. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  464. data/sig/phronomy/embeddings/base.rbs +17 -0
  465. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  466. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  467. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  468. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  469. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  470. data/sig/phronomy/engine/observability.rbs +13 -0
  471. data/sig/phronomy/execution/async_operation.rbs +7 -0
  472. data/sig/phronomy/execution/blocking.rbs +5 -0
  473. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  474. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  475. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  476. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  477. data/sig/phronomy/execution/errors.rbs +7 -0
  478. data/sig/phronomy/execution/execution.rbs +41 -0
  479. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  480. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  481. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  482. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  483. data/sig/phronomy/execution/task_result.rbs +29 -0
  484. data/sig/phronomy/extensions.rbs +0 -21
  485. data/sig/phronomy/handoff.rbs +12 -4
  486. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  487. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  488. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  489. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  490. data/sig/phronomy/llm_context_window.rbs +10 -0
  491. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  492. data/sig/phronomy/multi_agent/store.rbs +54 -0
  493. data/sig/phronomy/multi_agent.rbs +24 -3
  494. data/sig/phronomy/persistence/errors.rbs +18 -0
  495. data/sig/phronomy/persistence/migration.rbs +13 -0
  496. data/sig/phronomy/persistence/transaction.rbs +19 -0
  497. data/sig/phronomy/persistence.rbs +3 -185
  498. data/sig/phronomy/persistence_composition.rbs +19 -0
  499. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  500. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  501. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  502. data/sig/phronomy/storage/contracts.rbs +160 -0
  503. data/sig/phronomy/tool.rbs +58 -5
  504. data/sig/phronomy/tracing/observation.rbs +7 -0
  505. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  506. data/sig/phronomy/vector_store/base.rbs +23 -0
  507. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  508. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  509. data/sig/phronomy/workflow/store.rbs +8 -0
  510. data/sig/phronomy/workflow.rbs +1 -1
  511. data/sig/phronomy.rbs +0 -49
  512. metadata +462 -130
  513. data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
  514. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  515. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  516. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  517. data/lib/phronomy/agent/context/capability/base.rb +0 -507
  518. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  519. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  520. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  521. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  522. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  523. data/lib/phronomy/agent/handoff_request.rb +0 -45
  524. data/lib/phronomy/agent/handoff_runner.rb +0 -178
  525. data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
  526. data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
  527. data/lib/phronomy/agent/recovery_support.rb +0 -504
  528. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  529. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  530. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  531. data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
  532. data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
  533. data/lib/phronomy/configuration.rb +0 -59
  534. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  535. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  536. data/lib/phronomy/generator_verifier.rb +0 -369
  537. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  538. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  539. data/lib/phronomy/metrics.rb +0 -26
  540. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  541. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  542. data/lib/phronomy/persistence/in_memory.rb +0 -690
  543. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  544. data/lib/phronomy/persistence.rb +0 -276
  545. data/lib/phronomy/recovery.rb +0 -186
  546. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  547. data/lib/phronomy/runnable.rb +0 -54
  548. data/lib/phronomy/token_usage.rb +0 -85
  549. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  550. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  551. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  552. data/lib/phronomy/workflow_recovery.rb +0 -123
  553. data/sig/phronomy/llm_adapter.rbs +0 -11
  554. data/sig/phronomy/runtime.rbs +0 -76
  555. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  556. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  557. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
@@ -1,584 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Agent
5
- class AgentInvocationSessionBuilder
6
- AUTO_STATE_SET = {
7
- idle: true,
8
- filtering_input: true,
9
- building_context: true,
10
- starting_tools: true,
11
- evaluating_tools: true,
12
- recording_tool_results: true,
13
- output_filtering: true
14
- }.freeze
15
-
16
- DECLARED_STATES = %i[
17
- idle filtering_input building_context calling_llm starting_tools
18
- evaluating_tools waiting_for_tools dispatching_tools
19
- recording_tool_results suspended output_filtering handed_off completed blocked failed
20
- ].freeze
21
-
22
- WAIT_STATES = %i[suspended].freeze
23
-
24
- TOOL_EVENTS = %i[
25
- tool_authorized
26
- tool_approval_required
27
- tool_completed
28
- tool_failed
29
- tool_rejected
30
- tool_cancelled
31
- ].freeze
32
-
33
- def self.build(
34
- agent:,
35
- input:,
36
- config:,
37
- approval_policy: nil,
38
- approval_listener: nil,
39
- mode: :invoke,
40
- on_event: nil,
41
- runtime: Phronomy::Runtime.instance
42
- )
43
- invocation = AgentInvocation.new(
44
- agent: agent,
45
- input: input,
46
- config: config,
47
- approval_policy: approval_policy,
48
- approval_listener: approval_listener,
49
- event_listener: on_event,
50
- mode: mode,
51
- execution_id: config.fetch(:execution_id)
52
- )
53
- build_session(
54
- agent_invocation: invocation,
55
- runtime: runtime,
56
- mode: mode
57
- )
58
- end
59
-
60
- def self.build_for_resume(
61
- agent_invocation:,
62
- resume_event:,
63
- resume_phase:,
64
- runtime: Phronomy::Runtime.instance
65
- )
66
- build_session(
67
- agent_invocation: agent_invocation,
68
- runtime: runtime,
69
- mode: agent_invocation.mode,
70
- resume_event: resume_event,
71
- resume_phase: resume_phase
72
- )
73
- end
74
-
75
- def self.build_session(
76
- agent_invocation:,
77
- runtime:,
78
- mode:,
79
- resume_event: nil,
80
- resume_phase: nil
81
- )
82
- agent = agent_invocation.agent
83
- event_sink = Phronomy::FSMSession::EventSink.new(
84
- event_loop: runtime.event_loop
85
- )
86
- agent_invocation.bind_event_sink!(event_sink)
87
- actions = build_entry_actions(
88
- agent, runtime, mode: mode, event_sink: event_sink
89
- )
90
- phase_machine = Agent::PhaseMachineBuilder.new(entry_actions: actions).build
91
- iterations = agent.class.max_iterations || 10
92
-
93
- Phronomy::FSMSession.new(
94
- context: agent_invocation,
95
- event_sink: event_sink,
96
- entry_point: :idle,
97
- phase_machine_class: phase_machine,
98
- entry_actions: {},
99
- auto_state_set: AUTO_STATE_SET,
100
- declared_states: DECLARED_STATES,
101
- wait_state_names: WAIT_STATES,
102
- external_events: external_events,
103
- recursion_limit: 12 + (iterations * 8),
104
- event_loop: runtime.event_loop,
105
- resume_event: resume_event,
106
- resume_phase: resume_phase
107
- )
108
- end
109
- private_class_method :build_session
110
-
111
- def self.external_events
112
- tool_transitions = TOOL_EVENTS.to_h do |event_name|
113
- [event_name, [{from: :waiting_for_tools, to: :evaluating_tools, guard: nil}]]
114
- end
115
-
116
- tool_transitions.merge(
117
- llm_completed: [
118
- {from: :calling_llm, to: :failed, guard: ->(ctx) { ctx.callback_failed? }},
119
- {from: :calling_llm, to: :failed, guard: ->(ctx) { ctx.handoff_failed? }},
120
- {from: :calling_llm, to: :handed_off, guard: ->(ctx) { ctx.handoff_requested? }},
121
- {from: :calling_llm, to: :starting_tools, guard: ->(ctx) { ctx.tool_call_pending? }},
122
- {from: :calling_llm, to: :output_filtering, guard: nil}
123
- ],
124
- llm_failed: [
125
- {from: :calling_llm, to: :failed, guard: nil}
126
- ],
127
- llm_setup_failed: [
128
- {from: :calling_llm, to: :failed, guard: nil}
129
- ],
130
- tool_setup_failed: [
131
- {from: :dispatching_tools, to: :failed, guard: nil}
132
- ],
133
- tool_dispatch_prepared: [
134
- {from: :dispatching_tools, to: :evaluating_tools, guard: nil}
135
- ],
136
- resume: [
137
- {from: :suspended, to: :waiting_for_tools, guard: nil}
138
- ],
139
- application_callback_failed: [
140
- {from: :filtering_input, to: :failed, guard: nil},
141
- {from: :building_context, to: :failed, guard: nil},
142
- {from: :calling_llm, to: :failed, guard: nil},
143
- {from: :starting_tools, to: :failed, guard: nil},
144
- {from: :evaluating_tools, to: :failed, guard: nil},
145
- {from: :waiting_for_tools, to: :failed, guard: nil},
146
- {from: :dispatching_tools, to: :failed, guard: nil},
147
- {from: :recording_tool_results, to: :failed, guard: nil},
148
- {from: :output_filtering, to: :failed, guard: nil}
149
- ]
150
- )
151
- end
152
- private_class_method :external_events
153
-
154
- def self.build_entry_actions(agent, runtime, mode:, event_sink:)
155
- calling_action = if mode.to_sym == :stream
156
- method(:calling_llm_stream_action).curry.call(agent, runtime, event_sink)
157
- else
158
- method(:calling_llm_action).curry.call(agent, runtime, event_sink)
159
- end
160
-
161
- {
162
- filtering_input: [method(:filtering_input_action).curry.call(agent)],
163
- building_context: [method(:building_context_action).curry.call(agent)],
164
- calling_llm: [calling_action],
165
- starting_tools: [method(:starting_tools_action).curry.call(runtime, event_sink)],
166
- dispatching_tools: [method(:dispatching_tools_action).curry.call(runtime, event_sink)],
167
- recording_tool_results: [method(:recording_tool_results_action)],
168
- suspended: [method(:suspended_action)],
169
- output_filtering: [method(:output_filtering_action).curry.call(agent)],
170
- failed: [method(:failed_action)]
171
- }
172
- end
173
- private_class_method :build_entry_actions
174
-
175
- def self.filtering_input_action(_agent, invocation)
176
- invocation.input = invocation.config.fetch(:phronomy_filtered_input)
177
- invocation
178
- end
179
- private_class_method :filtering_input_action
180
-
181
- def self.building_context_action(agent, invocation)
182
- projection = invocation.config.fetch(:phronomy_runtime_projection)
183
- invocation.chat = agent.send(:build_chat, model_config: projection.model_config)
184
- agent.send(
185
- :_apply_runtime_projection_to_chat,
186
- invocation.chat,
187
- projection,
188
- invocation: invocation
189
- )
190
- invocation
191
- end
192
- private_class_method :building_context_action
193
-
194
- def self.install_tool_interceptors(chat, llm_call_id:)
195
- unless chat.respond_to?(:before_tool_call)
196
- raise Phronomy::ConfigurationError,
197
- "Agent-owned Tool execution requires RubyLLM >= 1.15 (before_tool_call callback)"
198
- end
199
-
200
- if chat.respond_to?(:on_tool_call_batch)
201
- chat.on_tool_call_batch do |tool_calls|
202
- raise build_tool_interception(chat, tool_calls, llm_call_id)
203
- end
204
- end
205
-
206
- chat.before_tool_call do |tool_call|
207
- raise build_tool_interception(chat, [tool_call], llm_call_id)
208
- end
209
- end
210
- private_class_method :install_tool_interceptors
211
-
212
- def self.build_tool_interception(chat, fallback_tool_calls, llm_call_id)
213
- assistant_message = chat.messages.last
214
- unless assistant_message&.respond_to?(:role) &&
215
- assistant_message.role.to_sym == :assistant &&
216
- assistant_message.respond_to?(:tool_calls)
217
- raise Phronomy::Error,
218
- "RubyLLM Tool callback fired before the complete assistant message was observable"
219
- end
220
-
221
- message_tool_calls = assistant_message.tool_calls
222
- tool_calls = message_tool_calls.respond_to?(:values) ? message_tool_calls.values : Array(message_tool_calls)
223
- tool_calls = Array(fallback_tool_calls) if tool_calls.empty?
224
-
225
- ToolCallIntercepted.new(
226
- tool_calls,
227
- assistant_message: assistant_message,
228
- assistant_outcome: ProviderCallOutcome.capture(assistant_message),
229
- llm_call_id: llm_call_id
230
- )
231
- end
232
- private_class_method :build_tool_interception
233
-
234
- def self.calling_llm_action(agent, runtime, event_sink, invocation)
235
- prepare_and_start_llm_call(agent, runtime, event_sink, invocation, streaming: false)
236
- invocation
237
- end
238
- private_class_method :calling_llm_action
239
-
240
- def self.calling_llm_stream_action(agent, runtime, event_sink, invocation)
241
- prepare_and_start_llm_call(agent, runtime, event_sink, invocation, streaming: true)
242
- invocation
243
- end
244
- private_class_method :calling_llm_stream_action
245
-
246
- def self.prepare_and_start_llm_call(agent, runtime, event_sink, invocation, streaming:)
247
- # Callback failure is recorded synchronously on EventLoop before its
248
- # explicit failure event is queued. Do not start a competing durable
249
- # follow-up operation from the same execution revision while that failure
250
- # event is waiting to terminalize the FSMSession.
251
- return if invocation.callback_failed?
252
-
253
- if invocation.user_message_sent
254
- invocation.config.fetch(:phronomy_execution_coordinator).prepare_provider_dispatch(
255
- invocation,
256
- event_sink: event_sink,
257
- streaming: streaming
258
- )
259
- else
260
- start_provider_call(
261
- agent,
262
- runtime,
263
- event_sink,
264
- invocation,
265
- invocation.config.fetch(:phronomy_runtime_projection),
266
- streaming: streaming,
267
- replace_messages: false
268
- )
269
- end
270
- rescue => error
271
- post_setup_failure(event_sink, error)
272
- end
273
- private_class_method :prepare_and_start_llm_call
274
-
275
- # Continues a follow-up Provider Call after its durable preparation result
276
- # has been validated/applied by ExecutionCoordinator on EventLoop.
277
- # @api private
278
- def self.start_prepared_provider_call(
279
- agent:,
280
- runtime:,
281
- event_sink:,
282
- invocation:,
283
- projection:,
284
- streaming:
285
- )
286
- start_provider_call(
287
- agent,
288
- runtime,
289
- event_sink,
290
- invocation,
291
- projection,
292
- streaming: streaming,
293
- replace_messages: true
294
- )
295
- end
296
-
297
- def self.start_provider_call(
298
- agent, runtime, event_sink, invocation, projection,
299
- streaming:, replace_messages:
300
- )
301
- call_context = trace_handle = nil
302
- config = invocation.config
303
- agent.send(:check_cancellation!, config, "invocation cancelled before LLM call")
304
- if replace_messages
305
- invocation.chat = agent.send(:build_chat, model_config: projection.model_config)
306
- agent.send(
307
- :_apply_runtime_projection_to_chat,
308
- invocation.chat,
309
- projection,
310
- invocation: invocation
311
- )
312
- invocation.config[:phronomy_runtime_projection] = projection
313
- end
314
-
315
- call_context = invocation.begin_llm_call!(projection)
316
- install_tool_interceptors(
317
- invocation.chat,
318
- llm_call_id: call_context.fetch(:llm_call_id)
319
- )
320
- message = projection.ask_message
321
- chat = invocation.chat
322
- trace_handle = Phronomy::Tracing::Automatic.start(
323
- "llm.call",
324
- input: message,
325
- agent_id: agent.agent_id,
326
- execution_id: invocation.execution_id,
327
- llm_call_id: call_context.fetch(:llm_call_id),
328
- mode: invocation.mode,
329
- streaming: streaming,
330
- **agent.send(:_build_caller_meta, config)
331
- )
332
-
333
- operation = if streaming
334
- Phronomy.configuration.llm_adapter.stream_async(
335
- chat, message, config: config
336
- ) do |chunk|
337
- token = config[:cancellation_token]
338
- token&.raise_if_cancelled!("invocation cancelled during streaming")
339
- post_stream_chunk(
340
- event_sink,
341
- call_context.fetch(:llm_call_id),
342
- chunk.content
343
- )
344
- end
345
- else
346
- Phronomy.configuration.llm_adapter.complete_async(
347
- chat, message, config: config
348
- )
349
- end
350
- runtime.event_loop.supervise_agent_operation(
351
- invocation.execution_id,
352
- operation
353
- )
354
- observe_manifest_call(
355
- operation,
356
- event_sink,
357
- call_context,
358
- trace_handle,
359
- streaming: streaming
360
- )
361
- rescue => error
362
- finish_provider_trace(trace_handle, nil, error)
363
- if call_context
364
- post_llm_result(
365
- event_sink,
366
- call_context,
367
- nil,
368
- error,
369
- streaming: streaming
370
- )
371
- else
372
- post_setup_failure(event_sink, error)
373
- end
374
- end
375
- private_class_method :start_provider_call
376
-
377
- def self.observe_manifest_call(
378
- operation,
379
- event_sink,
380
- call_context,
381
- trace_handle,
382
- streaming:
383
- )
384
- operation.on_complete do |response, error|
385
- finish_provider_trace(trace_handle, response, error)
386
- post_llm_result(
387
- event_sink,
388
- call_context,
389
- response,
390
- error,
391
- streaming: streaming
392
- )
393
- end
394
- end
395
- private_class_method :observe_manifest_call
396
-
397
- def self.finish_provider_trace(trace_handle, response, error)
398
- control_transfer = error.is_a?(ToolCallIntercepted)
399
- trace_output = control_transfer ?
400
- (error.assistant_outcome || error.assistant_message) : response
401
- trace_error = control_transfer ? nil : error
402
- usage_source = control_transfer ? error.assistant_message : response
403
- usage = if usage_source&.respond_to?(:tokens)
404
- Phronomy::TokenUsage.from_tokens(usage_source.tokens)
405
- end
406
- Phronomy::Tracing::Automatic.finish(
407
- trace_handle,
408
- output: trace_output,
409
- usage: usage,
410
- error: trace_error
411
- )
412
- end
413
- private_class_method :finish_provider_trace
414
-
415
- def self.post_llm_result(event_sink, call_context, response, error, streaming:)
416
- result = LLMOperationResult.new(
417
- llm_call_id: call_context.fetch(:llm_call_id),
418
- response: response,
419
- error: error,
420
- streaming: streaming
421
- )
422
- event_type = if error && !error.is_a?(ToolCallIntercepted)
423
- :llm_failed
424
- else
425
- :llm_completed
426
- end
427
- post_session_event!(event_sink, event_type, result)
428
- end
429
- private_class_method :post_llm_result
430
-
431
- def self.post_stream_chunk(event_sink, llm_call_id, content)
432
- post_session_event!(
433
- event_sink,
434
- :llm_stream_chunk,
435
- {llm_call_id: llm_call_id.to_s.freeze, content: content}.freeze
436
- )
437
- end
438
- private_class_method :post_stream_chunk
439
-
440
- def self.post_setup_failure(event_sink, error)
441
- post_session_event!(event_sink, :llm_setup_failed, error)
442
- end
443
- private_class_method :post_setup_failure
444
-
445
- def self.post_session_event!(event_sink, event_type, payload)
446
- return if event_sink.post(event_type, payload)
447
-
448
- Phronomy.configuration.logger&.warn(
449
- "[Phronomy] Dropped late #{event_type.inspect} for " \
450
- "FSMSession #{event_sink.fsm_session_id}"
451
- )
452
- end
453
- private_class_method :post_session_event!
454
-
455
- def self.starting_tools_action(runtime, parent_event_sink, invocation)
456
- children = invocation.pending_tool_calls.map do |tool_call|
457
- tool = invocation.chat.tools[tool_call.name.to_sym]
458
- tool_invocation_id =
459
- RecoverySupport.semantic_tool_id(
460
- execution_id: invocation.execution_id,
461
- llm_call_id: invocation.tool_batch_llm_call_id,
462
- tool_call_id: (
463
- tool_call.respond_to?(:id) ? tool_call.id : nil
464
- ),
465
- tool_name: tool_call.name
466
- )
467
-
468
- if tool
469
- ToolInvocation.new(
470
- execution_id: invocation.execution_id,
471
- agent: invocation.agent,
472
- tool: tool,
473
- tool_call: tool_call,
474
- config: invocation.config,
475
- approval_policy: invocation.approval_policy,
476
- approval_context: invocation.approval_context,
477
- id: tool_invocation_id
478
- )
479
- else
480
- ToolInvocation.missing(
481
- execution_id: invocation.execution_id,
482
- agent: invocation.agent,
483
- tool_call: tool_call,
484
- config: invocation.config,
485
- id: tool_invocation_id
486
- )
487
- end
488
- end
489
- invocation.tool_invocations = children
490
-
491
- children.reject(&:terminal?).each do |child|
492
- session = ToolInvocationSessionBuilder.build(
493
- tool_invocation: child,
494
- parent_event_sink: parent_event_sink,
495
- runtime: runtime
496
- )
497
- register_child_session(
498
- runtime,
499
- child,
500
- session,
501
- parent_event_sink
502
- )
503
- end
504
- invocation
505
- end
506
- private_class_method :starting_tools_action
507
-
508
- def self.dispatching_tools_action(_runtime, parent_event_sink, invocation)
509
- invocation.config.fetch(:phronomy_execution_coordinator).prepare_tool_dispatch(
510
- invocation,
511
- event_sink: parent_event_sink
512
- )
513
- invocation
514
- end
515
- private_class_method :dispatching_tools_action
516
-
517
- # Continues Tool physical dispatch after the operation-specific durable
518
- # preparation has been confirmed and applied by ExecutionCoordinator.
519
- # @api private
520
- def self.start_prepared_tool_dispatch(
521
- runtime:,
522
- event_sink:,
523
- invocation:
524
- )
525
- invocation.tool_invocations.select(&:authorized?).each do |child|
526
- session = ToolInvocationSessionBuilder.build_for_resume(
527
- tool_invocation: child,
528
- parent_event_sink: event_sink,
529
- resume_event: :dispatch,
530
- resume_phase: :authorized,
531
- runtime: runtime
532
- )
533
- begin
534
- register_child_session(runtime, child, session, event_sink)
535
- rescue => error
536
- child.mark_framework_failed!(error)
537
- event_sink.post(:tool_failed, {tool_invocation_id: child.id})
538
- end
539
- end
540
- post_session_event!(event_sink, :tool_dispatch_prepared, nil)
541
- invocation
542
- end
543
-
544
- def self.register_child_session(runtime, child, session, parent_event_sink)
545
- completion = Phronomy::TaskResult.deferred(name: "tool-session:#{child.id}")
546
- completion.on_complete do |_result, error|
547
- next unless error
548
-
549
- # Tool FSMSession completion is settled by EventLoop, so this callback
550
- # also executes on EventLoop and remains inside the single-writer domain.
551
- child.mark_framework_failed!(error)
552
- parent_event_sink.post(:tool_failed, {tool_invocation_id: child.id})
553
- end
554
- runtime.event_loop.register(session, completion: completion)
555
- end
556
- private_class_method :register_child_session
557
-
558
- def self.recording_tool_results_action(invocation)
559
- invocation.record_tool_results!
560
- end
561
- private_class_method :recording_tool_results_action
562
-
563
- def self.suspended_action(invocation)
564
- invocation.prepare_approval_request!
565
- end
566
- private_class_method :suspended_action
567
-
568
- def self.failed_action(invocation)
569
- raise(invocation.error || Phronomy::ToolError.new("Agent invocation failed"))
570
- end
571
- private_class_method :failed_action
572
-
573
- def self.output_filtering_action(agent, invocation)
574
- invocation.output = agent.send(:run_output_filters!, invocation.output)
575
- invocation
576
- rescue Phronomy::FilterBlockError => error
577
- invocation.output_blocked = true
578
- invocation.block_error = error
579
- invocation
580
- end
581
- private_class_method :output_filtering_action
582
- end
583
- end
584
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Agent
5
- module Concerns
6
- module BeforeLLMInput
7
- def self.included(base)
8
- base.extend(ClassMethods)
9
- end
10
-
11
- module ClassMethods
12
- def before_llm_input(callable = nil, &block)
13
- if callable.nil? && !block_given?
14
- @before_llm_input
15
- else
16
- @before_llm_input = callable || block
17
- end
18
- end
19
-
20
- def _before_llm_input = @before_llm_input
21
- end
22
-
23
- attr_accessor :before_llm_input
24
-
25
- private
26
-
27
- def run_before_llm_input_hooks(call_sequence:, config:)
28
- hooks = [
29
- Phronomy.configuration.before_llm_input,
30
- self.class._before_llm_input,
31
- @before_llm_input
32
- ].compact
33
- return LLMInputPatch.empty if hooks.empty?
34
-
35
- definition = self.class.agent_definition
36
- context = LLMInputBuildContext.new(
37
- agent_id: agent_id,
38
- agent_definition_id: definition.fetch(:id),
39
- agent_definition_version: definition.fetch(:version),
40
- config: config,
41
- call_sequence: call_sequence
42
- )
43
- model_patch = {}
44
- segments = []
45
-
46
- hooks.each do |hook|
47
- result = hook.call(context)
48
- check_cancellation!(config, "invocation cancelled during before_llm_input hook")
49
- next if result.nil?
50
- unless result.is_a?(LLMInputPatch)
51
- raise TypeError,
52
- "before_llm_input must return LLMInputPatch or nil, got #{result.class}"
53
- end
54
- model_patch.merge!(result.model_config_patch) if result.model_config_patch
55
- segments.concat(Array(result.segment_candidates))
56
- end
57
-
58
- LLMInputPatch.new(
59
- model_config_patch: model_patch.empty? ? nil : model_patch,
60
- segment_candidates: segments.empty? ? nil : segments
61
- )
62
- end
63
- end
64
- end
65
- end
66
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Agent
5
- module Concerns
6
- # Translates RubyLLM transport errors into the corresponding Phronomy error
7
- # classes so that callers can rescue Phronomy-namespaced exceptions rather
8
- # than coupling themselves to the underlying provider library.
9
- #
10
- # Included in {Phronomy::Agent::Base}.
11
- module ErrorTranslation
12
- private
13
-
14
- # Re-raises +error+ as the most specific Phronomy error class that
15
- # corresponds to it. Non-RubyLLM errors are re-raised unchanged.
16
- # The original exception is available as +#cause+ on the translated error.
17
- #
18
- # Must be called from within an active +rescue+ block so that Ruby
19
- # automatically sets +#cause+ on the new exception.
20
- #
21
- # @param error [Exception]
22
- # @raise [Phronomy::RateLimitError] for provider HTTP 429
23
- # @raise [Phronomy::AuthenticationError] for provider HTTP 401 / 403
24
- # @raise [Phronomy::ContextLengthError] for context window overflow
25
- # @raise [Phronomy::TransportError] for all other +RubyLLM::Error+ subclasses
26
- # @raise re-raises +error+ unchanged for non-RubyLLM exceptions
27
- # @api private
28
- def translate_and_reraise!(error)
29
- case error
30
- when RubyLLM::RateLimitError
31
- raise Phronomy::RateLimitError, error.message
32
- when RubyLLM::UnauthorizedError, RubyLLM::ForbiddenError
33
- raise Phronomy::AuthenticationError, error.message
34
- when RubyLLM::ContextLengthExceededError
35
- raise Phronomy::ContextLengthError, error.message
36
- when RubyLLM::Error
37
- raise Phronomy::TransportError, error.message
38
- else
39
- raise error # preserve original class, message, and backtrace
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end