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.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +92 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +13 -3
- data/VERIFY.sh +27 -27
- data/benchmark/bench_agent_invoke.rb +26 -47
- data/benchmark/bench_context_assembler.rb +17 -15
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
- data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
- data/docs/architecture/agent-context.md +4 -2
- data/docs/architecture/agent-transition-ownership.md +13 -0
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +9 -3
- data/docs/architecture/context-management.md +31 -1
- data/docs/architecture/context-preparation-steps.md +90 -0
- data/docs/architecture/entry-action-and-team-wording.md +72 -0
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +86 -0
- data/docs/architecture/generator-verifier-ownership.md +111 -0
- data/docs/architecture/multi-agent-handoff.md +11 -4
- data/docs/architecture/persistence-refactoring-plan.md +50 -0
- data/docs/architecture/persistence.md +45 -4
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +343 -0
- data/docs/architecture/remaining-refactoring-plan.md +390 -0
- data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +56 -0
- data/docs/architecture/tracing.md +2 -2
- data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
- data/docs/architecture.md +222 -0
- data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
- data/docs/decisions/032-storage-backend-composition.md +85 -0
- data/docs/decisions/033-domain-persistence-ownership.md +79 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
- data/docs/decisions/036-context-contract-ownership.md +86 -0
- data/docs/decisions/037-common-definition-ownership.md +62 -0
- data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
- data/docs/decisions/040-configuration-default-composition.md +105 -0
- data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
- data/docs/decisions/042-feature-owned-execution-state.md +106 -0
- data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
- data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
- data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
- data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
- data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
- data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
- data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
- data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
- data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
- data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
- data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
- data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
- data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
- data/docs/decisions/058-neutral-storage-primitives.md +83 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +52 -6
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/features.md +16 -5
- data/docs/getting-started.md +11 -8
- data/docs/migrations/0.15.md +5 -0
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
- data/docs/migrations/handoff-runner-multi-agent.md +37 -0
- data/docs/migrations/neutral-storage-spi.md +43 -0
- data/docs/migrations/parallel-tool-chat-removal.md +49 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/shared-state-multi-agent.md +44 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/storage-backend-composition.md +117 -0
- data/docs/migrations/storage-transaction-boundaries.md +74 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/persistence-backends.md +190 -215
- data/docs/runtime-and-concurrency.md +142 -32
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
- data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
- data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
- data/lib/phronomy/agent/api/agent.rb +17 -0
- data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
- data/lib/phronomy/agent/async_event_api.rb +38 -33
- data/lib/phronomy/agent/base.rb +106 -294
- data/lib/phronomy/agent/before_llm_input.rb +64 -0
- data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
- data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
- data/lib/phronomy/agent/context_importer.rb +2 -2
- data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
- data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
- data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
- data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
- data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
- data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
- data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
- data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
- data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
- data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
- data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
- data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +182 -0
- data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
- data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
- data/lib/phronomy/agent/handoff_error.rb +7 -0
- data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
- data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
- data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
- data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
- data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
- data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +338 -0
- data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
- data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
- data/lib/phronomy/agent/persistence/watermark.rb +29 -0
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
- data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
- data/lib/phronomy/agent/saved_context_reader.rb +55 -0
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/state_writer.rb +166 -0
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
- data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
- data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
- data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/common/configuration_error.rb +7 -0
- data/lib/phronomy/common/error.rb +5 -0
- data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
- data/lib/phronomy/common/values/serializable.rb +32 -0
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/storage_schema.rb +12 -0
- data/lib/phronomy/content_store/stored_contents.rb +44 -0
- data/lib/phronomy/context/assembly.rb +202 -0
- data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
- data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
- data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
- data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
- data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
- data/lib/phronomy/engine/event_loop.rb +164 -630
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +9 -0
- data/lib/phronomy/engine/fsm_session.rb +37 -30
- data/lib/phronomy/engine/metrics.rb +28 -0
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +104 -95
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/execution/backpressure_error.rb +7 -0
- data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
- data/lib/phronomy/execution/cancellation_error.rb +7 -0
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
- data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
- data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
- data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
- data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
- data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
- data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
- data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
- data/lib/phronomy/execution/timeout_error.rb +7 -0
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/filter_block_error.rb +14 -0
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
- data/lib/phronomy/generation/generator_verifier.rb +118 -0
- data/lib/phronomy/generation/low_confidence_error.rb +14 -0
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
- data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
- data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
- data/lib/phronomy/multi_agent/team_execution.rb +1 -1
- data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
- data/lib/phronomy/multi_agent/team_root.rb +1 -1
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +107 -0
- data/lib/phronomy/storage/backends/in_memory.rb +157 -0
- data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
- data/lib/phronomy/storage/blobs.rb +31 -0
- data/lib/phronomy/storage/condition.rb +25 -0
- data/lib/phronomy/storage/condition_failed_error.rb +16 -0
- data/lib/phronomy/storage/conflict_error.rb +9 -0
- data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
- data/lib/phronomy/storage/entry.rb +33 -0
- data/lib/phronomy/storage/guard_ref.rb +13 -0
- data/lib/phronomy/storage/not_found_error.rb +9 -0
- data/lib/phronomy/storage/record_codec.rb +177 -0
- data/lib/phronomy/storage/records.rb +61 -0
- data/lib/phronomy/storage/resource.rb +126 -0
- data/lib/phronomy/storage/scope.rb +25 -0
- data/lib/phronomy/storage/serialization_error.rb +9 -0
- data/lib/phronomy/storage/streams.rb +44 -0
- data/lib/phronomy/storage/transaction_error.rb +10 -0
- data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
- data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
- data/lib/phronomy/storage/validation.rb +53 -0
- data/lib/phronomy/storage/view.rb +131 -0
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
- data/lib/phronomy/testing/persistence_contract.rb +4 -0
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +549 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +1 -1
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
- data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
- data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/persistence/codec.rb +153 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
- data/lib/phronomy.rb +97 -98
- data/scripts/api_snapshot.rb +36 -16
- data/scripts/storage_spi_snapshot.rb +36 -0
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent.rbs +14 -139
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +17 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +0 -21
- data/sig/phronomy/handoff.rbs +12 -4
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent.rbs +24 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +3 -185
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/storage/contracts.rbs +160 -0
- data/sig/phronomy/tool.rbs +58 -5
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +1 -1
- data/sig/phronomy.rbs +0 -49
- metadata +462 -130
- data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -507
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
- data/lib/phronomy/agent/handoff_request.rb +0 -45
- data/lib/phronomy/agent/handoff_runner.rb +0 -178
- data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
- data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/recovery_support.rb +0 -504
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
- data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration.rb +0 -59
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/generator_verifier.rb +0 -369
- data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/metrics.rb +0 -26
- data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
- data/lib/phronomy/persistence/durable_codec.rb +0 -706
- data/lib/phronomy/persistence/in_memory.rb +0 -690
- data/lib/phronomy/persistence/repository_facades.rb +0 -535
- data/lib/phronomy/persistence.rb +0 -276
- data/lib/phronomy/recovery.rb +0 -186
- data/lib/phronomy/ruby_llm_patches.rb +0 -24
- data/lib/phronomy/runnable.rb +0 -54
- data/lib/phronomy/token_usage.rb +0 -85
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow_recovery.rb +0 -123
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
- /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
- /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
require "securerandom"
|
|
4
6
|
|
|
5
7
|
module Phronomy
|
|
@@ -12,13 +14,13 @@ module Phronomy
|
|
|
12
14
|
# - Runtime admission uses a separate opaque owner token.
|
|
13
15
|
#
|
|
14
16
|
# Workflow persistence is synchronous at the repository contract but is always
|
|
15
|
-
# invoked through
|
|
17
|
+
# invoked through its owning execution environment. Durable terminal save results return
|
|
16
18
|
# to the same FSMSession before that session becomes halted/completed.
|
|
17
19
|
# @api private
|
|
18
20
|
class WorkflowRunner
|
|
19
|
-
include Phronomy::
|
|
21
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
include Phronomy::Runnable
|
|
22
24
|
|
|
23
25
|
Execution = Data.define(
|
|
24
26
|
:context,
|
|
@@ -89,7 +91,8 @@ module Phronomy
|
|
|
89
91
|
@entry_point = entry_point
|
|
90
92
|
@wait_state_names = wait_state_names
|
|
91
93
|
@persistence = persistence
|
|
92
|
-
@
|
|
94
|
+
@environment = WorkflowExecutionEnvironment.current
|
|
95
|
+
@phase_machine_class = @environment.compile_transitions(
|
|
93
96
|
entry_point: @entry_point,
|
|
94
97
|
declared_states: @declared_states,
|
|
95
98
|
wait_state_names: @wait_state_names,
|
|
@@ -97,7 +100,7 @@ module Phronomy
|
|
|
97
100
|
entry_actions: @entry_actions,
|
|
98
101
|
auto_transitions: auto_transitions,
|
|
99
102
|
exit_actions: exit_actions
|
|
100
|
-
)
|
|
103
|
+
)
|
|
101
104
|
end
|
|
102
105
|
|
|
103
106
|
def invoke(input, config: {})
|
|
@@ -138,7 +141,7 @@ module Phronomy
|
|
|
138
141
|
end
|
|
139
142
|
|
|
140
143
|
# Posts an application-defined event to the currently live Workflow owner.
|
|
141
|
-
#
|
|
144
|
+
# WorkflowExecutionRegistry resolves workflow_instance_id to the current concrete
|
|
142
145
|
# fsm_session_id. The opaque admission owner token is deliberately not a
|
|
143
146
|
# routing identity and is not exposed here.
|
|
144
147
|
def signal(workflow_instance_id:, event:, payload: nil)
|
|
@@ -151,7 +154,10 @@ module Phronomy
|
|
|
151
154
|
"Valid events: #{@external_events.keys.inspect}"
|
|
152
155
|
end
|
|
153
156
|
|
|
154
|
-
|
|
157
|
+
registry = @environment.existing_registry
|
|
158
|
+
return false unless registry
|
|
159
|
+
|
|
160
|
+
registry.post_to_workflow(
|
|
155
161
|
workflow_instance_id: workflow_instance_id,
|
|
156
162
|
event: event_name,
|
|
157
163
|
payload: payload
|
|
@@ -163,8 +169,7 @@ module Phronomy
|
|
|
163
169
|
# progression therefore remain EventLoop-owned.
|
|
164
170
|
# @api private
|
|
165
171
|
def deliver_on_event_loop(command)
|
|
166
|
-
|
|
167
|
-
assert_event_loop!(event_loop)
|
|
172
|
+
assert_execution_owner!
|
|
168
173
|
|
|
169
174
|
case command
|
|
170
175
|
when StartCommand
|
|
@@ -206,7 +211,7 @@ module Phronomy
|
|
|
206
211
|
end
|
|
207
212
|
|
|
208
213
|
def ensure_blocking_call_allowed!(method_name, async_alternative)
|
|
209
|
-
return unless Phronomy::
|
|
214
|
+
return unless Phronomy::WaitPolicy.blocking_forbidden?
|
|
210
215
|
|
|
211
216
|
raise Phronomy::Error,
|
|
212
217
|
"Cannot call Workflow##{method_name} from the EventLoop thread. " \
|
|
@@ -215,7 +220,6 @@ module Phronomy
|
|
|
215
220
|
|
|
216
221
|
def start_new_execution(input, config, stable_observer: nil)
|
|
217
222
|
reject_legacy_workflow_identity_key!(config)
|
|
218
|
-
runtime = Phronomy::Runtime.instance
|
|
219
223
|
result_task = Phronomy::TaskResult.deferred(name: "workflow:preparing")
|
|
220
224
|
explicit_workflow_instance_id = !config[:workflow_instance_id].nil?
|
|
221
225
|
workflow_instance_id = (config[:workflow_instance_id] || SecureRandom.uuid).to_s.freeze
|
|
@@ -237,7 +241,7 @@ module Phronomy
|
|
|
237
241
|
owner_token: Object.new.freeze,
|
|
238
242
|
explicit_workflow_instance_id: explicit_workflow_instance_id
|
|
239
243
|
)
|
|
240
|
-
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(
|
|
244
|
+
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(command)
|
|
241
245
|
result_task
|
|
242
246
|
rescue => error
|
|
243
247
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -245,7 +249,6 @@ module Phronomy
|
|
|
245
249
|
end
|
|
246
250
|
|
|
247
251
|
def start_resume_execution(state, input:, event_name:, current_phase:)
|
|
248
|
-
runtime = Phronomy::Runtime.instance
|
|
249
252
|
workflow_instance_id = state.workflow_instance_id.to_s.freeze
|
|
250
253
|
result_task = Phronomy::TaskResult.deferred(name: "workflow-resume:#{workflow_instance_id}")
|
|
251
254
|
Phronomy::Tracing::Automatic.observe_task(
|
|
@@ -266,7 +269,7 @@ module Phronomy
|
|
|
266
269
|
workflow_instance_id: workflow_instance_id,
|
|
267
270
|
owner_token: Object.new.freeze
|
|
268
271
|
)
|
|
269
|
-
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(
|
|
272
|
+
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(command)
|
|
270
273
|
result_task
|
|
271
274
|
rescue => error
|
|
272
275
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -274,10 +277,8 @@ module Phronomy
|
|
|
274
277
|
end
|
|
275
278
|
|
|
276
279
|
def begin_start_on_event_loop(request)
|
|
277
|
-
runtime = Phronomy::Runtime.instance
|
|
278
|
-
event_loop = runtime.event_loop
|
|
279
280
|
admitted = false
|
|
280
|
-
|
|
281
|
+
@environment.registry.admit_workflow(
|
|
281
282
|
request.workflow_instance_id,
|
|
282
283
|
owner_token: request.owner_token
|
|
283
284
|
)
|
|
@@ -285,7 +286,7 @@ module Phronomy
|
|
|
285
286
|
|
|
286
287
|
recursion_limit = request.config.fetch(
|
|
287
288
|
:recursion_limit,
|
|
288
|
-
Phronomy.
|
|
289
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
289
290
|
)
|
|
290
291
|
repository = configured_repository
|
|
291
292
|
persist = request.explicit_workflow_instance_id && !repository.nil?
|
|
@@ -310,7 +311,6 @@ module Phronomy
|
|
|
310
311
|
end
|
|
311
312
|
|
|
312
313
|
submit_workflow_load(
|
|
313
|
-
runtime,
|
|
314
314
|
repository,
|
|
315
315
|
request.workflow_instance_id,
|
|
316
316
|
StartLoadReady,
|
|
@@ -318,7 +318,7 @@ module Phronomy
|
|
|
318
318
|
)
|
|
319
319
|
rescue => error
|
|
320
320
|
if admitted
|
|
321
|
-
|
|
321
|
+
@environment.registry.release_workflow(
|
|
322
322
|
request.workflow_instance_id,
|
|
323
323
|
owner_token: request.owner_token
|
|
324
324
|
)
|
|
@@ -327,10 +327,8 @@ module Phronomy
|
|
|
327
327
|
end
|
|
328
328
|
|
|
329
329
|
def begin_resume_on_event_loop(request)
|
|
330
|
-
runtime = Phronomy::Runtime.instance
|
|
331
|
-
event_loop = runtime.event_loop
|
|
332
330
|
admitted = false
|
|
333
|
-
|
|
331
|
+
@environment.registry.admit_workflow(
|
|
334
332
|
request.workflow_instance_id,
|
|
335
333
|
owner_token: request.owner_token
|
|
336
334
|
)
|
|
@@ -343,7 +341,7 @@ module Phronomy
|
|
|
343
341
|
context: context,
|
|
344
342
|
workflow_instance_id: request.workflow_instance_id,
|
|
345
343
|
owner_token: request.owner_token,
|
|
346
|
-
recursion_limit: Phronomy.
|
|
344
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
347
345
|
repository: nil,
|
|
348
346
|
persist: false,
|
|
349
347
|
expected_revision: nil
|
|
@@ -358,7 +356,6 @@ module Phronomy
|
|
|
358
356
|
end
|
|
359
357
|
|
|
360
358
|
submit_workflow_load(
|
|
361
|
-
runtime,
|
|
362
359
|
repository,
|
|
363
360
|
request.workflow_instance_id,
|
|
364
361
|
ResumeLoadReady,
|
|
@@ -366,7 +363,7 @@ module Phronomy
|
|
|
366
363
|
)
|
|
367
364
|
rescue => error
|
|
368
365
|
if admitted
|
|
369
|
-
|
|
366
|
+
@environment.registry.release_workflow(
|
|
370
367
|
request.workflow_instance_id,
|
|
371
368
|
owner_token: request.owner_token
|
|
372
369
|
)
|
|
@@ -374,12 +371,12 @@ module Phronomy
|
|
|
374
371
|
fail_task(request.result_task, error)
|
|
375
372
|
end
|
|
376
373
|
|
|
377
|
-
def submit_workflow_load(
|
|
374
|
+
def submit_workflow_load(repository, workflow_instance_id, ready_class, request)
|
|
378
375
|
operation = WorkflowLoadCommand.new(
|
|
379
376
|
repository: repository,
|
|
380
377
|
workflow_instance_id: workflow_instance_id.to_s.freeze
|
|
381
378
|
)
|
|
382
|
-
task =
|
|
379
|
+
task = @environment.submit(on_full: :raise) do
|
|
383
380
|
record = operation.repository.load(operation.workflow_instance_id)
|
|
384
381
|
WorkflowLoadResult.new(
|
|
385
382
|
repository: operation.repository,
|
|
@@ -395,7 +392,7 @@ module Phronomy
|
|
|
395
392
|
error: error
|
|
396
393
|
)
|
|
397
394
|
fail_task(request.result_task, runtime_rejected_error(:load_result)) unless
|
|
398
|
-
post_control(
|
|
395
|
+
post_control(ready)
|
|
399
396
|
end
|
|
400
397
|
nil
|
|
401
398
|
end
|
|
@@ -409,7 +406,7 @@ module Phronomy
|
|
|
409
406
|
|
|
410
407
|
recursion_limit = request.config.fetch(
|
|
411
408
|
:recursion_limit,
|
|
412
|
-
Phronomy.
|
|
409
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
413
410
|
)
|
|
414
411
|
execution = build_new_execution(
|
|
415
412
|
request.input,
|
|
@@ -447,7 +444,7 @@ module Phronomy
|
|
|
447
444
|
context: context,
|
|
448
445
|
workflow_instance_id: request.workflow_instance_id,
|
|
449
446
|
owner_token: request.owner_token,
|
|
450
|
-
recursion_limit: Phronomy.
|
|
447
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
451
448
|
repository: ready.result.repository,
|
|
452
449
|
persist: true,
|
|
453
450
|
expected_revision: expected_revision
|
|
@@ -503,7 +500,7 @@ module Phronomy
|
|
|
503
500
|
local_snapshot = normalize_snapshot(snapshot_for(state))
|
|
504
501
|
return durable_revision if normalized_durable == local_snapshot
|
|
505
502
|
|
|
506
|
-
raise Phronomy::Persistence::
|
|
503
|
+
raise Phronomy::Persistence::StateConflictError,
|
|
507
504
|
"Workflow state changed since the supplied halted context for " \
|
|
508
505
|
"workflow_instance_id #{state.workflow_instance_id.inspect}; explicit reload/reconciliation is required"
|
|
509
506
|
end
|
|
@@ -555,8 +552,7 @@ module Phronomy
|
|
|
555
552
|
end
|
|
556
553
|
|
|
557
554
|
def configured_repository
|
|
558
|
-
|
|
559
|
-
persistence&.workflow_states
|
|
555
|
+
@persistence || Phronomy::WorkflowSettings.current.workflow_store
|
|
560
556
|
end
|
|
561
557
|
|
|
562
558
|
def register_execution(
|
|
@@ -566,17 +562,14 @@ module Phronomy
|
|
|
566
562
|
resume_phase: nil,
|
|
567
563
|
stable_observer: nil
|
|
568
564
|
)
|
|
569
|
-
|
|
570
|
-
event_loop = runtime.event_loop
|
|
571
|
-
assert_event_loop!(event_loop)
|
|
565
|
+
assert_execution_owner!
|
|
572
566
|
session = build_session_for(
|
|
573
567
|
execution: execution,
|
|
574
|
-
runtime: runtime,
|
|
575
568
|
resume_event: resume_event,
|
|
576
569
|
resume_phase: resume_phase,
|
|
577
570
|
stable_observer: stable_observer
|
|
578
571
|
)
|
|
579
|
-
|
|
572
|
+
@environment.registry.bind_workflow_session(
|
|
580
573
|
execution.workflow_instance_id,
|
|
581
574
|
owner_token: execution.owner_token,
|
|
582
575
|
fsm_session_id: session.id
|
|
@@ -591,11 +584,11 @@ module Phronomy
|
|
|
591
584
|
error: error
|
|
592
585
|
)
|
|
593
586
|
end
|
|
594
|
-
|
|
587
|
+
@environment.register_session(session, completion: source_task)
|
|
595
588
|
result_task
|
|
596
589
|
rescue => error
|
|
597
|
-
if
|
|
598
|
-
|
|
590
|
+
if @environment.executing?
|
|
591
|
+
@environment.registry.release_workflow(
|
|
599
592
|
execution.workflow_instance_id,
|
|
600
593
|
owner_token: execution.owner_token
|
|
601
594
|
)
|
|
@@ -606,9 +599,8 @@ module Phronomy
|
|
|
606
599
|
# Called from source_task completion on EventLoop, after the FSMSession has
|
|
607
600
|
# accepted the durable terminal result (when a durable barrier is required).
|
|
608
601
|
def finalize_execution(execution:, result_task:, result:, error:)
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
event_loop.release_workflow(
|
|
602
|
+
assert_execution_owner!
|
|
603
|
+
@environment.registry.release_workflow(
|
|
612
604
|
execution.workflow_instance_id,
|
|
613
605
|
owner_token: execution.owner_token
|
|
614
606
|
)
|
|
@@ -621,76 +613,117 @@ module Phronomy
|
|
|
621
613
|
context:,
|
|
622
614
|
event_sink:
|
|
623
615
|
)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
assert_event_loop!(event_loop)
|
|
627
|
-
event_loop.mark_workflow_admission(
|
|
616
|
+
assert_execution_owner!
|
|
617
|
+
@environment.registry.mark_workflow_admission(
|
|
628
618
|
execution.workflow_instance_id,
|
|
629
619
|
owner_token: execution.owner_token,
|
|
630
620
|
state: :persisting_terminal
|
|
631
621
|
)
|
|
632
622
|
|
|
633
|
-
operation = WorkflowTerminalPersistenceCommand.new(
|
|
623
|
+
operation = Phronomy::WorkflowRunner::WorkflowTerminalPersistenceCommand.new(
|
|
634
624
|
repository: execution.repository,
|
|
635
625
|
workflow_instance_id: execution.workflow_instance_id.to_s.freeze,
|
|
636
626
|
expected_revision: execution.expected_revision,
|
|
637
627
|
snapshot: deep_immutable_copy(snapshot_for(context))
|
|
638
628
|
)
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
629
|
+
|
|
630
|
+
task = @environment.submit(on_full: :raise) do
|
|
631
|
+
persist_terminal_snapshot(operation)
|
|
632
|
+
end
|
|
633
|
+
task.on_complete do |result, operation_error|
|
|
634
|
+
deliver_terminal_persistence_result(execution, event_sink, result, operation_error)
|
|
635
|
+
end
|
|
636
|
+
terminal_type
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def persist_terminal_snapshot(operation)
|
|
640
|
+
revision = operation.repository.save(
|
|
641
|
+
operation.workflow_instance_id,
|
|
642
|
+
expected_revision: operation.expected_revision,
|
|
643
|
+
snapshot: operation.snapshot
|
|
644
|
+
)
|
|
645
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
646
|
+
outcome: :success,
|
|
647
|
+
revision: revision,
|
|
648
|
+
error: nil
|
|
649
|
+
)
|
|
650
|
+
rescue Phronomy::Persistence::ConflictError,
|
|
651
|
+
Phronomy::Persistence::NotFoundError,
|
|
652
|
+
Phronomy::Persistence::SerializationError,
|
|
653
|
+
Phronomy::Persistence::UnsupportedBackendError => error
|
|
654
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
655
|
+
outcome: :known_failure,
|
|
656
|
+
revision: nil,
|
|
657
|
+
error: error
|
|
658
|
+
)
|
|
659
|
+
rescue => error
|
|
660
|
+
reconcile_workflow_terminal_f1(operation, error)
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def deliver_terminal_persistence_result(execution, event_sink, result, operation_error)
|
|
664
|
+
delivery = if operation_error
|
|
665
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
666
|
+
outcome: :outcome_unknown,
|
|
667
|
+
revision: nil,
|
|
668
|
+
error: operation_error
|
|
669
|
+
)
|
|
670
|
+
else
|
|
671
|
+
result
|
|
672
|
+
end
|
|
673
|
+
accepted = event_sink.post(:workflow_terminal_persistence_result, delivery)
|
|
674
|
+
unless accepted
|
|
675
|
+
Phronomy::RuntimeSettings.current.logger&.warn(
|
|
676
|
+
"[Phronomy] EventLoop rejected Workflow terminal persistence result " \
|
|
677
|
+
"for #{execution.workflow_instance_id.inspect}"
|
|
644
678
|
)
|
|
645
|
-
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
def reconcile_workflow_terminal_f1(operation, original_error)
|
|
683
|
+
record = operation.repository.load(operation.workflow_instance_id)
|
|
684
|
+
case Phronomy::Persistence::SnapshotComparison.compare_revisioned_snapshot(
|
|
685
|
+
record: record,
|
|
686
|
+
expected_pre_revision: operation.expected_revision,
|
|
687
|
+
intended_snapshot: operation.snapshot
|
|
688
|
+
)
|
|
689
|
+
when :post_state
|
|
690
|
+
revision = Phronomy::Persistence::SnapshotComparison.fetch_value(record, :revision)
|
|
691
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
646
692
|
outcome: :success,
|
|
647
693
|
revision: revision,
|
|
648
694
|
error: nil
|
|
649
695
|
)
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
WorkflowTerminalPersistenceResult.new(
|
|
696
|
+
when :pre_state
|
|
697
|
+
# The uncertain save is now known not to have committed. Do not blindly
|
|
698
|
+
# retry it here; surface a known failure through the ordinary terminal
|
|
699
|
+
# barrier semantics.
|
|
700
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
655
701
|
outcome: :known_failure,
|
|
656
702
|
revision: nil,
|
|
657
|
-
error:
|
|
703
|
+
error: original_error
|
|
704
|
+
)
|
|
705
|
+
else
|
|
706
|
+
conflict = Phronomy::Persistence::StateConflictError.new(
|
|
707
|
+
"Workflow terminal Persistence outcome conflicts with both expected " \
|
|
708
|
+
"pre-state and intended post-state for #{operation.workflow_instance_id.inspect}"
|
|
658
709
|
)
|
|
659
|
-
|
|
660
|
-
# The Backend SPI does not currently provide a portable commit-outcome
|
|
661
|
-
# classifier for arbitrary storage/transport failures. If non-commit is
|
|
662
|
-
# not guaranteed by the Phronomy error contract, fail closed as F1.
|
|
663
|
-
WorkflowTerminalPersistenceResult.new(
|
|
710
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
664
711
|
outcome: :outcome_unknown,
|
|
665
712
|
revision: nil,
|
|
666
|
-
error:
|
|
713
|
+
error: conflict
|
|
667
714
|
)
|
|
668
715
|
end
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
)
|
|
676
|
-
else
|
|
677
|
-
result
|
|
678
|
-
end
|
|
679
|
-
accepted = event_sink.post(:workflow_terminal_persistence_result, delivery)
|
|
680
|
-
unless accepted
|
|
681
|
-
Phronomy.configuration.logger&.warn(
|
|
682
|
-
"[Phronomy] EventLoop rejected Workflow terminal persistence result " \
|
|
683
|
-
"for #{execution.workflow_instance_id.inspect}"
|
|
684
|
-
)
|
|
685
|
-
end
|
|
686
|
-
end
|
|
687
|
-
terminal_type
|
|
716
|
+
rescue => reconciliation_error
|
|
717
|
+
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
718
|
+
outcome: :outcome_unknown,
|
|
719
|
+
revision: nil,
|
|
720
|
+
error: reconciliation_error
|
|
721
|
+
)
|
|
688
722
|
end
|
|
689
723
|
|
|
690
724
|
def release_and_fail(request, error)
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
event_loop.release_workflow(
|
|
725
|
+
assert_execution_owner!
|
|
726
|
+
@environment.registry.release_workflow(
|
|
694
727
|
request.workflow_instance_id,
|
|
695
728
|
owner_token: request.owner_token
|
|
696
729
|
)
|
|
@@ -706,23 +739,11 @@ module Phronomy
|
|
|
706
739
|
|
|
707
740
|
def build_session_for(
|
|
708
741
|
execution:,
|
|
709
|
-
runtime:,
|
|
710
742
|
resume_event: nil,
|
|
711
743
|
resume_phase: nil,
|
|
712
744
|
stable_observer: nil
|
|
713
745
|
)
|
|
714
|
-
|
|
715
|
-
->(terminal_type:, context:, event_sink:) {
|
|
716
|
-
begin_terminal_persistence_on_event_loop(
|
|
717
|
-
execution,
|
|
718
|
-
terminal_type: terminal_type,
|
|
719
|
-
context: context,
|
|
720
|
-
event_sink: event_sink
|
|
721
|
-
)
|
|
722
|
-
}
|
|
723
|
-
end
|
|
724
|
-
|
|
725
|
-
Phronomy::FSMSession.new(
|
|
746
|
+
@environment.build_session(
|
|
726
747
|
context: execution.context,
|
|
727
748
|
context_metadata: {
|
|
728
749
|
workflow_instance_id: execution.workflow_instance_id
|
|
@@ -735,14 +756,26 @@ module Phronomy
|
|
|
735
756
|
external_events: @external_events,
|
|
736
757
|
phase_machine_class: @phase_machine_class,
|
|
737
758
|
recursion_limit: execution.recursion_limit,
|
|
738
|
-
event_loop: runtime.event_loop,
|
|
739
759
|
resume_event: resume_event,
|
|
740
760
|
resume_phase: resume_phase,
|
|
741
761
|
stable_observer: stable_observer,
|
|
742
|
-
|
|
762
|
+
persist: terminal_persistence_callback(execution)
|
|
743
763
|
)
|
|
744
764
|
end
|
|
745
765
|
|
|
766
|
+
def terminal_persistence_callback(execution)
|
|
767
|
+
return unless execution.repository && execution.persist
|
|
768
|
+
|
|
769
|
+
->(terminal_type:, context:, event_sink:) {
|
|
770
|
+
begin_terminal_persistence_on_event_loop(
|
|
771
|
+
execution,
|
|
772
|
+
terminal_type: terminal_type,
|
|
773
|
+
context: context,
|
|
774
|
+
event_sink: event_sink
|
|
775
|
+
)
|
|
776
|
+
}
|
|
777
|
+
end
|
|
778
|
+
|
|
746
779
|
def resolve_resume_event(current_phase, event)
|
|
747
780
|
event_name = event.to_sym
|
|
748
781
|
unless event_name == :resume
|
|
@@ -765,14 +798,11 @@ module Phronomy
|
|
|
765
798
|
"No external event registered for state #{current_phase.inspect}"
|
|
766
799
|
end
|
|
767
800
|
|
|
768
|
-
def post_control(
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
payload: {command: command}
|
|
774
|
-
)
|
|
775
|
-
)
|
|
801
|
+
def post_control(command)
|
|
802
|
+
admission = command.is_a?(StartCommand) || command.is_a?(ResumeCommand)
|
|
803
|
+
completion = admission ? command.result_task : command.request.result_task
|
|
804
|
+
@environment.registry.post(command,
|
|
805
|
+
admission: admission, completion: completion)
|
|
776
806
|
end
|
|
777
807
|
|
|
778
808
|
def runtime_rejected_error(action)
|
|
@@ -781,8 +811,8 @@ module Phronomy
|
|
|
781
811
|
)
|
|
782
812
|
end
|
|
783
813
|
|
|
784
|
-
def
|
|
785
|
-
return if
|
|
814
|
+
def assert_execution_owner!
|
|
815
|
+
return if @environment.executing?
|
|
786
816
|
|
|
787
817
|
raise Phronomy::Error,
|
|
788
818
|
"Workflow live-state progression must run on EventLoop"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Workflow-owned progress limit and optional state repository. Composition
|
|
5
|
+
# supplies these values; existing execution boundaries decide when to read.
|
|
6
|
+
# @api private
|
|
7
|
+
class WorkflowSettings
|
|
8
|
+
class << self
|
|
9
|
+
# Bind at boot without reading settings or starting runtime resources.
|
|
10
|
+
def install_provider(&provider)
|
|
11
|
+
raise ArgumentError, "settings provider requires a block" unless provider
|
|
12
|
+
@provider = provider
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Read only when requested; no cache or change notification is involved.
|
|
17
|
+
def current
|
|
18
|
+
@provider.call
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_accessor :recursion_limit, :workflow_store
|
|
23
|
+
|
|
24
|
+
def initialize(recursion_limit:)
|
|
25
|
+
@recursion_limit = recursion_limit
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|