phronomy 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +4 -0
  4. data/VERIFY.sh +27 -27
  5. data/benchmark/bench_agent_invoke.rb +26 -22
  6. data/benchmark/bench_context_assembler.rb +4 -5
  7. data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
  8. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  9. data/docs/architecture/agent-context.md +4 -2
  10. data/docs/architecture/agent-transition-ownership.md +89 -0
  11. data/docs/architecture/before-llm-input.md +6 -0
  12. data/docs/architecture/context-management.md +30 -0
  13. data/docs/architecture/context-preparation-steps.md +90 -0
  14. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  15. data/docs/architecture/execution-metadata-and-values.md +80 -0
  16. data/docs/architecture/generator-verifier-ownership.md +111 -0
  17. data/docs/architecture/multi-agent-handoff.md +8 -2
  18. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  19. data/docs/architecture/persistence.md +27 -4
  20. data/docs/architecture/refactoring-closure.md +334 -0
  21. data/docs/architecture/remaining-refactoring-plan.md +374 -0
  22. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  23. data/docs/architecture/tool-schema-recording-gap.md +50 -0
  24. data/docs/architecture/tracing.md +1 -1
  25. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  26. data/docs/architecture.md +209 -0
  27. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  28. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  29. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  30. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  31. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
  32. data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
  33. data/docs/decisions/032-storage-backend-composition.md +80 -0
  34. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  35. data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
  36. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  37. data/docs/decisions/036-context-contract-ownership.md +86 -0
  38. data/docs/decisions/037-common-definition-ownership.md +62 -0
  39. data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
  40. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
  41. data/docs/decisions/040-configuration-default-composition.md +94 -0
  42. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  43. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  44. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  45. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  46. data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
  47. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  48. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  49. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  50. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  51. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  52. data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
  53. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  54. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  55. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  56. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  57. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  58. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  59. data/docs/decisions/058-neutral-storage-primitives.md +78 -0
  60. data/docs/decisions/README.md +35 -6
  61. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  62. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  63. data/docs/features.md +9 -3
  64. data/docs/getting-started.md +4 -4
  65. data/docs/migrations/0.15.md +5 -0
  66. data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
  67. data/docs/migrations/handoff-runner-multi-agent.md +35 -0
  68. data/docs/migrations/neutral-storage-spi.md +43 -0
  69. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  70. data/docs/migrations/shared-state-multi-agent.md +44 -0
  71. data/docs/migrations/storage-backend-composition.md +117 -0
  72. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  73. data/docs/persistence-backends.md +162 -204
  74. data/docs/runtime-and-concurrency.md +117 -32
  75. data/lib/phronomy/agent/api/agent.rb +17 -0
  76. data/lib/phronomy/agent/async_event_api.rb +2 -2
  77. data/lib/phronomy/agent/base.rb +51 -241
  78. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  79. data/lib/phronomy/agent/context/capability/base.rb +67 -26
  80. data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
  81. data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
  82. data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
  83. data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
  84. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
  85. data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
  86. data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
  87. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
  88. data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
  89. data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
  90. data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
  91. data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
  92. data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
  93. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  94. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
  95. data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
  96. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  97. data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
  98. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
  99. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
  100. data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
  101. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  102. data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
  103. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
  104. data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
  105. data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
  106. data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
  107. data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
  108. data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
  109. data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
  110. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  111. data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
  112. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
  113. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
  114. data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
  115. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  116. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  117. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  118. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  119. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  120. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
  121. data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
  122. data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
  123. data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
  124. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
  125. data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
  126. data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
  127. data/lib/phronomy/agent/persistence/codec.rb +358 -0
  128. data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
  129. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
  130. data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
  131. data/lib/phronomy/agent/persistence/queries.rb +61 -0
  132. data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
  133. data/lib/phronomy/agent/persistence/watermark.rb +27 -0
  134. data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
  135. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
  136. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
  137. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
  138. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
  139. data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
  140. data/lib/phronomy/agent/selection/candidate.rb +1 -1
  141. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  142. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  143. data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
  144. data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
  145. data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
  146. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
  147. data/lib/phronomy/common/configuration_error.rb +7 -0
  148. data/lib/phronomy/common/error.rb +5 -0
  149. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  150. data/lib/phronomy/common/values/serializable.rb +32 -0
  151. data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
  152. data/lib/phronomy/configuration/global_configuration.rb +26 -0
  153. data/lib/phronomy/content_store/storage_schema.rb +11 -0
  154. data/lib/phronomy/content_store/stored_contents.rb +43 -0
  155. data/lib/phronomy/engine/backpressure_error.rb +7 -0
  156. data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
  157. data/lib/phronomy/engine/cancellation_error.rb +7 -0
  158. data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
  159. data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
  160. data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
  161. data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
  162. data/lib/phronomy/engine/event_loop.rb +158 -624
  163. data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
  164. data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
  165. data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
  166. data/lib/phronomy/engine/execution_receiver.rb +65 -0
  167. data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
  168. data/lib/phronomy/engine/fsm_protocol.rb +14 -0
  169. data/lib/phronomy/engine/fsm_session.rb +35 -28
  170. data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
  171. data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
  172. data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
  173. data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
  174. data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
  175. data/lib/phronomy/engine/runtime.rb +80 -84
  176. data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
  177. data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
  178. data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
  179. data/lib/phronomy/engine/task_result.rb +4 -0
  180. data/lib/phronomy/engine/timeout_error.rb +7 -0
  181. data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
  182. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  183. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  184. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  185. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  186. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  187. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  188. data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
  189. data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
  190. data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
  191. data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
  192. data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
  193. data/lib/phronomy/llm_contract/transport_error.rb +7 -0
  194. data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
  195. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
  196. data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
  197. data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
  198. data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
  199. data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
  200. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
  201. data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
  202. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  203. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
  204. data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
  205. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  206. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
  207. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  208. data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
  209. data/lib/phronomy/persistence/api/persistence.rb +140 -0
  210. data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
  211. data/lib/phronomy/persistence_composition/repositories.rb +77 -0
  212. data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
  213. data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
  214. data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
  215. data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
  216. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  217. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  218. data/lib/phronomy/storage/backend.rb +101 -0
  219. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  220. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  221. data/lib/phronomy/storage/blobs.rb +31 -0
  222. data/lib/phronomy/storage/condition.rb +25 -0
  223. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  224. data/lib/phronomy/storage/conflict_error.rb +9 -0
  225. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  226. data/lib/phronomy/storage/entry.rb +33 -0
  227. data/lib/phronomy/storage/guard_ref.rb +13 -0
  228. data/lib/phronomy/storage/not_found_error.rb +9 -0
  229. data/lib/phronomy/storage/record_codec.rb +177 -0
  230. data/lib/phronomy/storage/records.rb +61 -0
  231. data/lib/phronomy/storage/resource.rb +126 -0
  232. data/lib/phronomy/storage/scope.rb +25 -0
  233. data/lib/phronomy/storage/serialization_error.rb +9 -0
  234. data/lib/phronomy/storage/streams.rb +44 -0
  235. data/lib/phronomy/storage/transaction_error.rb +10 -0
  236. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  237. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  238. data/lib/phronomy/storage/validation.rb +53 -0
  239. data/lib/phronomy/storage/view.rb +131 -0
  240. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  241. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
  242. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
  243. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
  244. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
  245. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
  246. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
  247. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  248. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
  249. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  250. data/lib/phronomy/tool/contract/tool_error.rb +7 -0
  251. data/lib/phronomy/tools/agent.rb +1 -1
  252. data/lib/phronomy/version.rb +1 -1
  253. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
  254. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
  255. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  256. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
  257. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
  258. data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
  259. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  260. data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
  261. data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
  262. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
  263. data/lib/phronomy.rb +52 -94
  264. data/scripts/api_snapshot.rb +1 -1
  265. data/scripts/storage_spi_snapshot.rb +36 -0
  266. data/sig/phronomy/agent.rbs +0 -1
  267. data/sig/phronomy/execution_receiver.rbs +34 -0
  268. data/sig/phronomy/handoff.rbs +4 -2
  269. data/sig/phronomy/multi_agent.rbs +18 -0
  270. data/sig/phronomy/persistence.rbs +7 -91
  271. data/sig/phronomy/storage.rbs +174 -0
  272. data/sig/phronomy/tool.rbs +10 -1
  273. metadata +230 -99
  274. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  275. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  276. data/lib/phronomy/agent/recovery_support.rb +0 -504
  277. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  278. data/lib/phronomy/agent/tool_executor.rb +0 -55
  279. data/lib/phronomy/generator_verifier.rb +0 -369
  280. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  281. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  282. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  283. data/lib/phronomy/persistence/in_memory.rb +0 -690
  284. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  285. data/lib/phronomy/persistence.rb +0 -276
  286. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  287. data/lib/phronomy/workflow_recovery.rb +0 -123
  288. /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
  289. /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
  290. /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
  291. /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
  292. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  293. /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
  294. /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
  295. /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
  296. /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
  297. /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
  298. /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
  299. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  300. /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
  301. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
  302. /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
  303. /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
  304. /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ class Workflow
5
+ module Persistence
6
+ # Current-format record schemas and conversion for this domain.
7
+ # @api private
8
+ module Codec
9
+ extend Phronomy::Storage::RecordCodec
10
+
11
+ WORKFLOW_STATE_RECORD_TYPE = "phronomy.workflow_state"
12
+ WORKFLOW_STATE_FORMAT_VERSION = "0.1"
13
+ WORKFLOW_STATE_KEYS = %w[
14
+ workflow_instance_id workflow_revision snapshot
15
+ ].freeze
16
+
17
+ WORKFLOW_SNAPSHOT_KEYS = %w[fields phase].freeze
18
+
19
+ module_function
20
+
21
+ def encode_workflow_state(workflow_instance_id:, workflow_revision:, snapshot:)
22
+ normalized_snapshot = canonicalize_workflow_snapshot(snapshot)
23
+ validate_workflow_snapshot!(normalized_snapshot)
24
+ revision = Integer(workflow_revision)
25
+ unless revision.positive?
26
+ raise Phronomy::Storage::SerializationError,
27
+ "Workflow durable revision must be positive"
28
+ end
29
+
30
+ payload = {
31
+ "workflow_instance_id" => String(workflow_instance_id),
32
+ "workflow_revision" => revision,
33
+ "snapshot" => normalized_snapshot
34
+ }
35
+ validate_workflow_state_payload!(payload)
36
+ build_record(WORKFLOW_STATE_RECORD_TYPE, WORKFLOW_STATE_FORMAT_VERSION, payload)
37
+ rescue Phronomy::Storage::SerializationError
38
+ raise
39
+ rescue => error
40
+ serialization_error("cannot encode Workflow state", error)
41
+ end
42
+
43
+ def decode_workflow_state(record, expected_workflow_instance_id: nil)
44
+ payload = current_payload!(
45
+ record,
46
+ record_type: WORKFLOW_STATE_RECORD_TYPE,
47
+ format_version: WORKFLOW_STATE_FORMAT_VERSION,
48
+ keys: WORKFLOW_STATE_KEYS,
49
+ label: "Workflow state payload"
50
+ )
51
+ validate_workflow_state_payload!(payload)
52
+ workflow_instance_id = payload.fetch("workflow_instance_id")
53
+ if expected_workflow_instance_id &&
54
+ workflow_instance_id != expected_workflow_instance_id.to_s
55
+ raise Phronomy::Storage::SerializationError,
56
+ "Workflow state identity mismatch: #{workflow_instance_id.inspect} != " \
57
+ "#{expected_workflow_instance_id.to_s.inspect}"
58
+ end
59
+
60
+ {
61
+ snapshot: immutable_copy(payload.fetch("snapshot")),
62
+ revision: payload.fetch("workflow_revision")
63
+ }.freeze
64
+ rescue Phronomy::Storage::SerializationError
65
+ raise
66
+ rescue => error
67
+ serialization_error("cannot decode Workflow state", error)
68
+ end
69
+
70
+ def validate_workflow_state_payload!(payload)
71
+ validate_exact_keys!(payload, WORKFLOW_STATE_KEYS, label: "Workflow state payload")
72
+ require_nonempty_string!(payload, "workflow_instance_id", label: "Workflow state payload")
73
+ require_positive_integer!(payload, "workflow_revision", label: "Workflow state payload")
74
+ validate_workflow_snapshot!(payload.fetch("snapshot"))
75
+ payload
76
+ end
77
+
78
+ def validate_workflow_snapshot!(snapshot)
79
+ validate_exact_keys!(snapshot, WORKFLOW_SNAPSHOT_KEYS, label: "Workflow snapshot")
80
+ unless snapshot.fetch("fields").is_a?(Hash)
81
+ raise Phronomy::Storage::SerializationError,
82
+ "Workflow snapshot fields must be a Hash"
83
+ end
84
+ phase = snapshot.fetch("phase")
85
+ unless phase.nil? || phase.is_a?(String)
86
+ raise Phronomy::Storage::SerializationError,
87
+ "Workflow snapshot phase must be a String or nil"
88
+ end
89
+ Phronomy::CanonicalJSON.dump(snapshot)
90
+ snapshot
91
+ rescue ArgumentError => error
92
+ raise Phronomy::Storage::SerializationError,
93
+ "Workflow snapshot is not canonical JSON compatible: #{error.message}"
94
+ end
95
+
96
+ def canonicalize_workflow_snapshot(snapshot)
97
+ source = top_level_string_keys(snapshot, label: "Workflow snapshot")
98
+ fields = source.fetch("fields")
99
+ unless fields.is_a?(Hash)
100
+ raise Phronomy::Storage::SerializationError,
101
+ "Workflow snapshot fields must be a Hash"
102
+ end
103
+ {
104
+ "fields" => canonicalize_workflow_value(fields),
105
+ "phase" => source["phase"]&.to_s
106
+ }
107
+ end
108
+
109
+ def canonicalize_workflow_value(value)
110
+ case value
111
+ when Hash
112
+ value.each_with_object({}) do |(key, child), result|
113
+ unless key.is_a?(String) || key.is_a?(Symbol)
114
+ raise Phronomy::Storage::SerializationError,
115
+ "Workflow field key must be String or Symbol, got #{key.class}"
116
+ end
117
+ string_key = key.to_s
118
+ if result.key?(string_key)
119
+ raise Phronomy::Storage::SerializationError,
120
+ "duplicate Workflow field key after normalization: #{string_key.inspect}"
121
+ end
122
+ result[string_key] = canonicalize_workflow_value(child)
123
+ end
124
+ when Array
125
+ value.map { |child| canonicalize_workflow_value(child) }
126
+ when Symbol
127
+ value.to_s
128
+ when String, Integer, Float, TrueClass, FalseClass, NilClass
129
+ value
130
+ else
131
+ raise Phronomy::Storage::SerializationError,
132
+ "unsupported Workflow durable value: #{value.class}"
133
+ end
134
+ end
135
+
136
+ def immutable_copy(value)
137
+ case value
138
+ when Hash
139
+ value.each_with_object({}) do |(key, child), result|
140
+ result[key.dup.freeze] = immutable_copy(child)
141
+ end.freeze
142
+ when Array
143
+ value.map { |child| immutable_copy(child) }.freeze
144
+ when String
145
+ value.dup.freeze
146
+ else
147
+ value
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ class Workflow
5
+ module Persistence
6
+ # Owns Workflow snapshot encoding and the initial revision.
7
+ # @api private
8
+ class StateRepository
9
+ def initialize(view) = @view = view
10
+
11
+ def load(workflow_instance_id)
12
+ @view.atomic do |bound|
13
+ entry = bound.records(Phronomy::WorkflowStorageSchema::STATES).read(workflow_instance_id.to_s)
14
+ entry && decode(entry, workflow_instance_id)
15
+ end
16
+ end
17
+
18
+ def save(workflow_instance_id, expected_revision:, snapshot:)
19
+ expected = expected_revision.nil? ? nil : Integer(expected_revision)
20
+ revision = expected.nil? ? 1 : expected + 1
21
+ record = Codec.encode_workflow_state(workflow_instance_id: workflow_instance_id,
22
+ workflow_revision: revision, snapshot: snapshot)
23
+ @view.atomic do |bound|
24
+ records = bound.records(Phronomy::WorkflowStorageSchema::STATES)
25
+ values = {key: workflow_instance_id.to_s, attributes: {}, record: record}
26
+ entry = if expected.nil?
27
+ records.insert(**values, revision: revision)
28
+ else
29
+ records.replace(**values, expected_revision: expected, next_revision: revision)
30
+ end
31
+ decoded = decode(entry, workflow_instance_id)
32
+ unless decoded.fetch(:revision) == revision
33
+ raise Phronomy::Storage::SerializationError, "backend returned another Workflow revision"
34
+ end
35
+ revision
36
+ end
37
+ rescue Phronomy::Storage::NotFoundError => error
38
+ raise Phronomy::Storage::ConflictError, error.message
39
+ end
40
+
41
+ def delete(workflow_instance_id, expected_revision:)
42
+ @view.records(Phronomy::WorkflowStorageSchema::STATES).delete(key: workflow_instance_id.to_s, expected_revision: Integer(expected_revision))
43
+ end
44
+
45
+ private
46
+
47
+ def decode(entry, workflow_instance_id)
48
+ decoded = Codec.decode_workflow_state(entry.record, expected_workflow_instance_id: workflow_instance_id)
49
+ unless entry.key == workflow_instance_id.to_s && decoded.fetch(:revision) == entry.revision
50
+ raise Phronomy::Storage::SerializationError, "backend returned another Workflow identity/revision"
51
+ end
52
+ decoded
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -32,7 +32,7 @@ module Phronomy
32
32
 
33
33
  def build
34
34
  entry = @entry_point
35
- all_states = (@declared_states + @wait_state_names + [:__end__]).uniq
35
+ all_states = (@declared_states + @wait_state_names + [FSMProtocol::FINISH]).uniq
36
36
  auto_transitions = @auto_transitions
37
37
  external_events = @external_events
38
38
  entry_actions = @entry_actions
@@ -188,7 +188,7 @@ module Phronomy
188
188
  end
189
189
 
190
190
  def public_destination(destination)
191
- return :__finish__ if destination == Phronomy::WorkflowRunner::FINISH
191
+ return :__finish__ if destination == FSMProtocol::FINISH
192
192
 
193
193
  destination
194
194
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ # Domain-owned Workflow metadata, loadable without the Workflow runtime.
5
+ # @api private
6
+ module WorkflowStorageSchema
7
+ STATES = Phronomy::Storage::Resource.new(id: "workflow.states", kind: :records)
8
+ end
9
+ end
data/lib/phronomy.rb CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  require "zeitwerk"
4
4
  require "ruby_llm"
5
- require_relative "phronomy/ruby_llm_patches"
5
+ require_relative "phronomy/version"
6
6
 
7
7
  loader = Zeitwerk::Loader.for_gem
8
8
  loader.inflector.inflect("ruby_llm_embeddings" => "RubyLLMEmbeddings")
9
9
  loader.inflector.inflect("rag" => "RAG")
10
10
  loader.inflector.inflect("fsm_session" => "FSMSession")
11
+ loader.inflector.inflect("fsm_protocol" => "FSMProtocol")
11
12
  loader.inflector.inflect("llm_adapter" => "LLMAdapter")
12
13
  loader.inflector.inflect("llm_operation_result" => "LLMOperationResult")
13
14
  loader.inflector.inflect("ruby_llm" => "RubyLLM")
@@ -18,104 +19,61 @@ loader.inflector.inflect("llm_input_manifest" => "LLMInputManifest")
18
19
  loader.inflector.inflect("llm_input_build_context" => "LLMInputBuildContext")
19
20
  loader.inflector.inflect("llm_input_patch" => "LLMInputPatch")
20
21
  loader.inflector.inflect("before_llm_input" => "BeforeLLMInput")
21
- loader.collapse("#{__dir__}/phronomy/engine")
22
- # Loaded via require_relative before loader.setup; ignore to avoid Zeitwerk constant-name mismatch.
23
- loader.ignore("#{__dir__}/phronomy/ruby_llm_patches.rb")
24
- # Persistence backend conformance tests are explicit test support. Keep them out
25
- # of production eager-load so ordinary `require "phronomy"` never requires RSpec.
22
+ # These responsibility directories do not add a public Ruby namespace.
23
+ %w[common configuration engine generation llm_contract recovery].each do |directory|
24
+ loader.collapse("#{__dir__}/phronomy/#{directory}")
25
+ end
26
+ # Agent responsibility directories retain the existing Agent constant names.
27
+ %w[
28
+ context_contract lifecycle execution tool_execution context_assembly
29
+ journal handoff recovery
30
+ ].each do |directory|
31
+ loader.collapse("#{__dir__}/phronomy/agent/#{directory}")
32
+ end
33
+
34
+ # A nested root is independent of its enclosing Ruby namespace. Keep existing
35
+ # Phronomy::Workflow, Phronomy::WorkflowContext, and other canonical constants
36
+ # beside the feature they belong to, without aliases or a new partial-load API.
37
+ %w[
38
+ agent/api
39
+ agent/lifecycle_contract
40
+ filter/contract
41
+ output_parser/contract
42
+ persistence/api
43
+ tool/contract
44
+ workflow/execution
45
+ workflow/storage_contract
46
+ multi_agent/storage_contract
47
+ ].each do |directory|
48
+ loader.push_dir("#{__dir__}/phronomy/#{directory}", namespace: Phronomy)
49
+ end
50
+
51
+ # These files wire composition, reopen namespaces, or patch a dependency.
52
+ loader.ignore(
53
+ "#{__dir__}/phronomy/configuration/global_configuration.rb",
54
+ "#{__dir__}/phronomy/agent/composition",
55
+ "#{__dir__}/phronomy/runtime_composition/agent_defaults.rb",
56
+ "#{__dir__}/phronomy/runtime_composition/configuration_defaults.rb",
57
+ "#{__dir__}/phronomy/runtime_composition/global_runtime.rb"
58
+ )
59
+ # Persistence conformance support must never make production loading require RSpec.
26
60
  loader.ignore(
27
61
  "#{__dir__}/phronomy/testing/persistence_contract.rb",
28
62
  "#{__dir__}/phronomy/testing/persistence_contract"
29
63
  )
30
64
  loader.setup
31
65
 
32
- require_relative "phronomy/version"
33
- require_relative "phronomy/token_usage"
34
-
35
- module Phronomy
36
- class Error < StandardError; end
37
- class ParseError < Error; end
38
- class RecursionLimitError < Error; end
39
- class ToolError < Error; end
40
- class TimeoutError < Error; end
41
- class ConfigurationError < Error; end
42
- class HandoffError < Error; end
43
-
44
- class TransportError < Error; end
45
- class RateLimitError < TransportError; end
46
- class AuthenticationError < TransportError; end
47
- class ContextLengthError < Error; end
48
- class CancellationError < Error; end
49
-
50
- # Raised when a synchronous API would block the EventLoop control thread.
51
- class EventLoopReentrancyError < Error; end
52
-
53
- # Backward-compatible error class name for callers that still rescue the old
54
- # scheduler-oriented exception. New code should use EventLoopReentrancyError.
55
- class SchedulerReentrancyError < EventLoopReentrancyError; end
66
+ require_relative "phronomy/runtime_composition/configuration_defaults"
67
+ require_relative "phronomy/llm_contract/token_usage"
68
+ require_relative "phronomy/configuration/global_configuration"
69
+ require_relative "phronomy/runtime_composition/global_runtime"
56
70
 
57
- class RuntimeShutdownError < Error; end
58
- class RuntimeShutdownReentrancyError < RuntimeShutdownError; end
59
-
60
- class LowConfidenceError < Error
61
- attr_reader :result
62
-
63
- def initialize(result)
64
- @result = result
65
- super("Answer confidence #{result.confidence} is below the required threshold")
66
- end
67
- end
68
-
69
- class FilterBlockError < Error
70
- attr_reader :filter
71
-
72
- def initialize(message, filter: nil)
73
- super(message)
74
- @filter = filter
75
- end
76
- end
77
-
78
- class PoolShutdownError < Error; end
79
- class BackpressureError < Error; end
80
-
81
- class WorkflowContextOwnershipError < Error; end
82
-
83
- class << self
84
- def configuration
85
- @configuration ||= Configuration.new
86
- end
87
-
88
- def configure
89
- yield configuration
90
- end
91
-
92
- def reset_configuration!
93
- @configuration = Configuration.new
94
- end
95
-
96
- def with_configuration
97
- original = @configuration&.dup
98
- yield configuration
99
- ensure
100
- @configuration = original
101
- end
102
-
103
- def reset_runtime!(timeout: configuration.event_loop_stop_grace_seconds)
104
- previous_grace = @configuration&.event_loop_stop_grace_seconds
105
- result = Runtime.reset_default!(timeout: timeout)
106
-
107
- new_configuration = Configuration.new
108
- if previous_grace
109
- new_configuration.event_loop_stop_grace_seconds = previous_grace
110
- end
111
- @configuration = new_configuration
112
- result
113
- end
114
- end
115
- end
71
+ # Explicitly install the Agent namespace extensions even if its factory
72
+ # contract was loaded first. Composition owns both concrete binding and the
73
+ # run_once method definition; neither is required from Agent execution files.
74
+ require_relative "phronomy/agent/api/agent"
75
+ require_relative "phronomy/runtime_composition/agent_defaults"
76
+ require_relative "phronomy/agent/composition/run_once"
116
77
 
117
- # Shared Recovery primitives and Workflow Persistence F1 reconciliation.
118
- # Entity-specific Agent Recovery is loaded from lib/phronomy/agent.rb when the
119
- # Agent namespace is materialized.
120
- require_relative "phronomy/recovery"
121
- require_relative "phronomy/workflow_recovery"
78
+ # Load the common recovery vocabulary during ordinary application loading.
79
+ require_relative "phronomy/recovery/recovery"
@@ -36,7 +36,7 @@ PUBLIC_API_ENTRIES = [
36
36
  # Beta
37
37
  Phronomy::Agent::Handoff,
38
38
  Phronomy::Agent::HandoffPolicy,
39
- Phronomy::Agent::HandoffRunner,
39
+ Phronomy::MultiAgent::HandoffRunner,
40
40
  Phronomy::MultiAgent::Orchestrator,
41
41
  Phronomy::MultiAgent::TeamCoordinator,
42
42
  Phronomy::Filter::Base,
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require_relative "../lib/phronomy"
6
+
7
+ # Explicit SPI 2 scope, independent of the Stable/Beta product API snapshot.
8
+ # Private dispatch and domain composition helpers are deliberately excluded.
9
+ surfaces = {
10
+ Phronomy::Persistence => Phronomy::Persistence.public_instance_methods(false).sort,
11
+ Phronomy::Storage::Backend => %i[initialize capabilities transaction resources view],
12
+ Phronomy::Storage::Backends::InMemory => %i[initialize capabilities],
13
+ Phronomy::Storage::View => %i[records streams blobs check!],
14
+ Phronomy::Storage::Resource => %i[initialize id kind attributes immutable_attributes indexes unique guard validate_attributes index_values],
15
+ Phronomy::Storage::Records => %i[resource insert read fetch replace delete scan delete_matching],
16
+ Phronomy::Storage::Streams => %i[resource append read head delete],
17
+ Phronomy::Storage::Blobs => %i[resource put_if_absent fetch exist?],
18
+ Phronomy::Storage::GuardRef => %i[initialize resource key],
19
+ Phronomy::Storage::Condition::RevisionIs => %i[initialize resource key expected],
20
+ Phronomy::Storage::Condition::StreamHeadIs => %i[initialize resource stream expected],
21
+ Phronomy::Storage::Condition::NoRows => %i[initialize resource index equals],
22
+ Phronomy::Storage::Entry::Record => %i[initialize key revision attributes record],
23
+ Phronomy::Storage::Entry::Stream => %i[initialize position id record],
24
+ Phronomy::Storage::Entry::Append => %i[initialize id record],
25
+ Phronomy::Storage::Entry::Blob => %i[initialize key bytes attributes],
26
+ Phronomy::Storage::UniqueConstraintError => %i[initialize resource constraint],
27
+ Phronomy::Storage::ConditionFailedError => %i[initialize condition]
28
+ }
29
+ snapshot = {spi_version: 2, capabilities: Phronomy::Storage::Backend::REQUIRED_CAPABILITIES,
30
+ surfaces: surfaces.to_h { |type, names| [type.name, names.sort.to_h { |name| [name, type.instance_method(name).parameters] }] }}
31
+ json = JSON.pretty_generate(snapshot) + "\n"
32
+ if ARGV.include?("--write")
33
+ File.write(File.expand_path("../spec/fixtures/storage_spi_v2_snapshot.json", __dir__), json)
34
+ else
35
+ puts json
36
+ end
@@ -190,7 +190,6 @@ module Phronomy
190
190
  def self.max_iterations: (?Integer value) -> Integer
191
191
  def self.cache_instructions: (?bool enabled) -> bool?
192
192
  def self.max_output_tokens: (?Integer value) -> Integer?
193
- def self.context_window: (?Integer value) -> Integer?
194
193
  def self.context_policy: () -> ContextPolicy
195
194
  | (ContextPolicy policy) -> ContextPolicy
196
195
  def self.agent_definition: () -> Hash[Symbol, untyped]
@@ -0,0 +1,34 @@
1
+ module Phronomy
2
+ # Internal Engine contract (ADR-042); not an application extension SPI.
3
+ class ExecutionReceiver
4
+ def self.for: (EventLoop event_loop) -> instance
5
+ def self.existing_for: (Runtime runtime) -> instance?
6
+ def initialize: (event_loop: EventLoop) -> void
7
+ def __bound_to?: (EventLoop event_loop) -> bool
8
+ def idle?: () -> bool
9
+ def deliver: (untyped message) -> untyped
10
+ def shutdown: (error: Exception?) -> untyped
11
+ def session_retired: (String fsm_session_id, reason: Symbol) -> untyped
12
+
13
+ private
14
+
15
+ def synchronize: [V] () { () -> V } -> V
16
+ def admit: [V] () { () -> V } -> V
17
+ def post_message: (untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
18
+ def assert_event_loop_thread!: () -> void
19
+ end
20
+
21
+ class EventLoop
22
+ def __execution_receiver: (key: untyped) -> ExecutionReceiver?
23
+ def __register_execution_receiver: (key: untyped, receiver: ExecutionReceiver) -> ExecutionReceiver
24
+ def __synchronize_execution_state: [V] () { () -> V } -> V
25
+ def __admit_execution: [V] (ExecutionReceiver receiver) { () -> V } -> V
26
+ def __post_execution: (ExecutionReceiver receiver, untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
27
+ def __route_execution_event: (ExecutionReceiver receiver) { () -> untyped } -> bool
28
+ def __receiver_cleanup_complete?: () -> bool
29
+ end
30
+
31
+ class Runtime
32
+ def __event_loop_if_initialized: () -> EventLoop?
33
+ end
34
+ end
@@ -25,14 +25,16 @@ module Phronomy
25
25
  def selectable_categories: () -> Array[Symbol]
26
26
  def to_h: () -> Hash[String, Hash[String, String]]
27
27
  end
28
+ end
28
29
 
30
+ module MultiAgent
29
31
  class HandoffRunner
30
32
  MAX_HANDOFFS: Integer
31
33
 
32
34
  attr_reader main_agent: ::Phronomy::Agent::Base
33
- attr_reader handoffs: Array[Handoff]
35
+ attr_reader handoffs: Array[::Phronomy::Agent::Handoff]
34
36
 
35
- def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[Handoff]) -> void
37
+ def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[::Phronomy::Agent::Handoff]) -> void
36
38
  def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
37
39
  def result: (String execution_id) -> Hash[Symbol, untyped]
38
40
  def cancel: (String execution_id) -> Hash[Symbol, untyped]
@@ -1,5 +1,23 @@
1
1
  module Phronomy
2
2
  module MultiAgent
3
+ class SharedState
4
+ class KnowledgeStore
5
+ def self.new: () -> instance
6
+ def read_all: () -> Array[Hash[Symbol, untyped]]
7
+ def write: (agent: untyped, content: untyped, cycle: untyped) -> nil
8
+ def size: () -> Integer
9
+ end
10
+
11
+ def self.new: () -> instance
12
+ def self.member: (singleton(::Phronomy::Agent::Base) klass, ?instruction: untyped) -> Array[Hash[Symbol, untyped]]
13
+ def self.coordination: (?untyped text) -> untyped
14
+ def self.max_cycles: (?untyped value) -> Integer?
15
+ def self.timeout: (?untyped value) -> Float?
16
+ def self.terminate_when: () ?{ (KnowledgeStore) -> untyped } -> untyped
17
+ def self.aggregate: () ?{ (KnowledgeStore) -> untyped } -> untyped
18
+ def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
19
+ end
20
+
3
21
  class Orchestrator < ::Phronomy::Agent::Base
4
22
  def self.subagent: (Symbol | String name, singleton(::Phronomy::Agent::Base) agent_class, ?on_error: Symbol, ?inherit_knowledge: bool) -> untyped
5
23
  def self.registered_subagents: () -> Hash[Symbol | String, untyped]