phronomy 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +28 -7
- data/benchmark/bench_agent_invoke.rb +25 -50
- data/benchmark/bench_context_assembler.rb +14 -11
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/application-recipes.md +229 -0
- data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
- data/docs/architecture/agent-transition-ownership.md +13 -89
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +3 -3
- data/docs/architecture/context-management.md +1 -1
- data/docs/architecture/dx05-agent-scope.md +119 -0
- data/docs/architecture/dx05-workflow-task-state.md +134 -0
- data/docs/architecture/error-api-review.md +245 -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 +6 -0
- data/docs/architecture/multi-agent-handoff.md +6 -5
- data/docs/architecture/persistence.md +27 -9
- 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 +10 -1
- data/docs/architecture/remaining-refactoring-plan.md +16 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +6 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
- data/docs/architecture.md +24 -11
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
- data/docs/decisions/032-storage-backend-composition.md +5 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
- data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
- data/docs/decisions/040-configuration-default-composition.md +12 -1
- data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
- data/docs/decisions/058-neutral-storage-primitives.md +5 -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 +18 -1
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/failure-reason-codes.md +45 -0
- data/docs/features.md +12 -4
- data/docs/getting-started.md +52 -48
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
- data/docs/migrations/handoff-runner-multi-agent.md +2 -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/storage-async-client.md +103 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/ordered-event-delivery.md +54 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/docs/workflow-completion.md +92 -0
- data/gemfiles/http_minimum.gemfile +5 -0
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
- data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
- data/lib/phronomy/agent/api/agent.rb +13 -0
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +132 -103
- data/lib/phronomy/agent/base.rb +146 -113
- data/lib/phronomy/agent/before_llm_input.rb +70 -0
- data/lib/phronomy/agent/composition/run_once.rb +1 -1
- data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
- data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
- data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
- data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
- data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
- data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
- data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
- data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
- data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
- 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 +188 -0
- data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
- data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
- data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
- data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
- data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
- data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
- data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
- data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
- data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
- data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
- data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +1 -21
- data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
- data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
- 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 +7 -2
- data/lib/phronomy/agent/persistence/watermark.rb +13 -11
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
- 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/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
- data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
- 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/error.rb +65 -1
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/base.rb +7 -2
- data/lib/phronomy/content_store/storage_schema.rb +1 -0
- data/lib/phronomy/content_store/stored_contents.rb +2 -1
- data/lib/phronomy/context/assembly.rb +195 -0
- data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
- data/lib/phronomy/{agent/context_assembly → 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_contract → context}/llm_input_build_context.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
- data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
- 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/authentication_error.rb +11 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/engine/diagnostics.rb +1 -1
- data/lib/phronomy/engine/event_loop.rb +7 -7
- 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 +1 -6
- data/lib/phronomy/engine/fsm_session.rb +3 -3
- data/lib/phronomy/engine/metrics.rb +16 -14
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +25 -12
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -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/{engine → execution}/execution.rb +61 -27
- data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
- data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
- data/lib/phronomy/generation/generator_verifier.rb +7 -7
- data/lib/phronomy/generation/low_confidence_error.rb +2 -2
- data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
- 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/multi_agent/admission_registry.rb +1 -8
- 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/handoff → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +20 -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 +60 -44
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
- 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/multi_agent/shared_state.rb +2 -2
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
- data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
- data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
- 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 +2 -2
- 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 +9 -4
- 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 +5 -1
- data/lib/phronomy/runtime_composition/configuration.rb +146 -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/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 +8 -2
- data/lib/phronomy/storage/condition_failed_error.rb +2 -2
- data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
- 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 +2 -2
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +551 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
- 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/tool/tool_executor.rb +58 -0
- 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 +36 -7
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
- 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/execution/workflow.rb +37 -9
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
- data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
- data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
- data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +63 -16
- data/scripts/api_snapshot.rb +47 -15
- data/scripts/check_readme_ruby.rb +24 -29
- data/scripts/check_readme_runnable.rb +92 -81
- 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/agent_not_found_error.rbs +6 -0
- data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -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/stream_callback_error.rbs +8 -0
- data/sig/phronomy/agent.rbs +29 -135
- 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 +23 -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 +1 -21
- data/sig/phronomy/filter/filter_block_error.rbs +6 -0
- data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/integrations.rbs +14 -0
- 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/team_busy_error.rbs +8 -0
- data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
- data/sig/phronomy/multi_agent.rbs +6 -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 +1 -99
- 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.rbs → storage/contracts.rbs} +4 -18
- data/sig/phronomy/tool.rbs +48 -4
- 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 +15 -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 +5 -1
- data/sig/phronomy.rbs +4 -49
- metadata +365 -117
- 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 -548
- data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
- 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/phase_machine_builder.rb +0 -101
- data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
- data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
- data/lib/phronomy/agent/persistence/queries.rb +0 -61
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration/configuration.rb +0 -68
- data/lib/phronomy/configuration/global_configuration.rb +0 -26
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/engine/execution_receiver.rb +0 -65
- data/lib/phronomy/engine/runnable.rb +0 -54
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/llm_contract/token_usage.rb +0 -85
- data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
- data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
- data/lib/phronomy/persistence/api/persistence.rb +0 -140
- data/lib/phronomy/persistence_composition/repositories.rb +0 -77
- data/lib/phronomy/recovery/recovery.rb +0 -186
- data/lib/phronomy/tool/contract/tool_error.rb +0 -7
- 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/storage_contract/workflow_storage_schema.rb +0 -9
- data/sig/phronomy/execution_receiver.rbs +0 -34
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
- /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
- /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
4
|
|
|
5
5
|
require "securerandom"
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ module Phronomy
|
|
|
14
14
|
# - Runtime admission uses a separate opaque owner token.
|
|
15
15
|
#
|
|
16
16
|
# Workflow persistence is synchronous at the repository contract but is always
|
|
17
|
-
# invoked through
|
|
17
|
+
# invoked through its owning execution environment. Durable terminal save results return
|
|
18
18
|
# to the same FSMSession before that session becomes halted/completed.
|
|
19
19
|
# @api private
|
|
20
20
|
class WorkflowRunner
|
|
@@ -29,8 +29,13 @@ module Phronomy
|
|
|
29
29
|
:recursion_limit,
|
|
30
30
|
:repository,
|
|
31
31
|
:persist,
|
|
32
|
-
:expected_revision
|
|
33
|
-
|
|
32
|
+
:expected_revision,
|
|
33
|
+
:cancellation_token
|
|
34
|
+
) do
|
|
35
|
+
def initialize(cancellation_token: nil, **fields)
|
|
36
|
+
super(**fields, cancellation_token: cancellation_token)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
34
39
|
|
|
35
40
|
# API/callback -> EventLoop control messages.
|
|
36
41
|
StartCommand = Data.define(
|
|
@@ -79,6 +84,7 @@ module Phronomy
|
|
|
79
84
|
entry_point:,
|
|
80
85
|
exit_actions: {},
|
|
81
86
|
wait_state_names: [],
|
|
87
|
+
task_states: {},
|
|
82
88
|
persistence: nil
|
|
83
89
|
)
|
|
84
90
|
@state_class = state_class
|
|
@@ -90,8 +96,10 @@ module Phronomy
|
|
|
90
96
|
@external_events = external_events
|
|
91
97
|
@entry_point = entry_point
|
|
92
98
|
@wait_state_names = wait_state_names
|
|
99
|
+
@task_states = task_states
|
|
93
100
|
@persistence = persistence
|
|
94
|
-
@
|
|
101
|
+
@environment = WorkflowExecutionEnvironment.current
|
|
102
|
+
@phase_machine_class = @environment.compile_transitions(
|
|
95
103
|
entry_point: @entry_point,
|
|
96
104
|
declared_states: @declared_states,
|
|
97
105
|
wait_state_names: @wait_state_names,
|
|
@@ -99,7 +107,7 @@ module Phronomy
|
|
|
99
107
|
entry_actions: @entry_actions,
|
|
100
108
|
auto_transitions: auto_transitions,
|
|
101
109
|
exit_actions: exit_actions
|
|
102
|
-
)
|
|
110
|
+
)
|
|
103
111
|
end
|
|
104
112
|
|
|
105
113
|
def invoke(input, config: {})
|
|
@@ -125,6 +133,7 @@ module Phronomy
|
|
|
125
133
|
def send_event(state:, event:, input: nil)
|
|
126
134
|
ensure_blocking_call_allowed!(:send_event, :signal)
|
|
127
135
|
current_phase = state.phase.to_sym
|
|
136
|
+
reject_task_resume!(current_phase)
|
|
128
137
|
event_name = resolve_resume_event(current_phase, event)
|
|
129
138
|
workflow_instance_id = state.workflow_instance_id
|
|
130
139
|
unless workflow_instance_id
|
|
@@ -153,7 +162,7 @@ module Phronomy
|
|
|
153
162
|
"Valid events: #{@external_events.keys.inspect}"
|
|
154
163
|
end
|
|
155
164
|
|
|
156
|
-
registry =
|
|
165
|
+
registry = @environment.existing_registry
|
|
157
166
|
return false unless registry
|
|
158
167
|
|
|
159
168
|
registry.post_to_workflow(
|
|
@@ -168,8 +177,7 @@ module Phronomy
|
|
|
168
177
|
# progression therefore remain EventLoop-owned.
|
|
169
178
|
# @api private
|
|
170
179
|
def deliver_on_event_loop(command)
|
|
171
|
-
|
|
172
|
-
assert_event_loop!(event_loop)
|
|
180
|
+
assert_execution_owner!
|
|
173
181
|
|
|
174
182
|
case command
|
|
175
183
|
when StartCommand
|
|
@@ -211,7 +219,7 @@ module Phronomy
|
|
|
211
219
|
end
|
|
212
220
|
|
|
213
221
|
def ensure_blocking_call_allowed!(method_name, async_alternative)
|
|
214
|
-
return unless Phronomy::
|
|
222
|
+
return unless Phronomy::WaitPolicy.blocking_forbidden?
|
|
215
223
|
|
|
216
224
|
raise Phronomy::Error,
|
|
217
225
|
"Cannot call Workflow##{method_name} from the EventLoop thread. " \
|
|
@@ -220,7 +228,6 @@ module Phronomy
|
|
|
220
228
|
|
|
221
229
|
def start_new_execution(input, config, stable_observer: nil)
|
|
222
230
|
reject_legacy_workflow_identity_key!(config)
|
|
223
|
-
runtime = Phronomy::Runtime.instance
|
|
224
231
|
result_task = Phronomy::TaskResult.deferred(name: "workflow:preparing")
|
|
225
232
|
explicit_workflow_instance_id = !config[:workflow_instance_id].nil?
|
|
226
233
|
workflow_instance_id = (config[:workflow_instance_id] || SecureRandom.uuid).to_s.freeze
|
|
@@ -242,7 +249,7 @@ module Phronomy
|
|
|
242
249
|
owner_token: Object.new.freeze,
|
|
243
250
|
explicit_workflow_instance_id: explicit_workflow_instance_id
|
|
244
251
|
)
|
|
245
|
-
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(
|
|
252
|
+
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(command)
|
|
246
253
|
result_task
|
|
247
254
|
rescue => error
|
|
248
255
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -250,7 +257,6 @@ module Phronomy
|
|
|
250
257
|
end
|
|
251
258
|
|
|
252
259
|
def start_resume_execution(state, input:, event_name:, current_phase:)
|
|
253
|
-
runtime = Phronomy::Runtime.instance
|
|
254
260
|
workflow_instance_id = state.workflow_instance_id.to_s.freeze
|
|
255
261
|
result_task = Phronomy::TaskResult.deferred(name: "workflow-resume:#{workflow_instance_id}")
|
|
256
262
|
Phronomy::Tracing::Automatic.observe_task(
|
|
@@ -271,7 +277,7 @@ module Phronomy
|
|
|
271
277
|
workflow_instance_id: workflow_instance_id,
|
|
272
278
|
owner_token: Object.new.freeze
|
|
273
279
|
)
|
|
274
|
-
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(
|
|
280
|
+
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(command)
|
|
275
281
|
result_task
|
|
276
282
|
rescue => error
|
|
277
283
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -279,10 +285,8 @@ module Phronomy
|
|
|
279
285
|
end
|
|
280
286
|
|
|
281
287
|
def begin_start_on_event_loop(request)
|
|
282
|
-
runtime = Phronomy::Runtime.instance
|
|
283
|
-
event_loop = runtime.event_loop
|
|
284
288
|
admitted = false
|
|
285
|
-
|
|
289
|
+
@environment.registry.admit_workflow(
|
|
286
290
|
request.workflow_instance_id,
|
|
287
291
|
owner_token: request.owner_token
|
|
288
292
|
)
|
|
@@ -290,7 +294,7 @@ module Phronomy
|
|
|
290
294
|
|
|
291
295
|
recursion_limit = request.config.fetch(
|
|
292
296
|
:recursion_limit,
|
|
293
|
-
Phronomy.
|
|
297
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
294
298
|
)
|
|
295
299
|
repository = configured_repository
|
|
296
300
|
persist = request.explicit_workflow_instance_id && !repository.nil?
|
|
@@ -304,7 +308,8 @@ module Phronomy
|
|
|
304
308
|
repository: repository,
|
|
305
309
|
persist: false,
|
|
306
310
|
loaded_snapshot: nil,
|
|
307
|
-
expected_revision: nil
|
|
311
|
+
expected_revision: nil,
|
|
312
|
+
cancellation_token: request.config[:cancellation_token]
|
|
308
313
|
)
|
|
309
314
|
register_execution(
|
|
310
315
|
execution,
|
|
@@ -315,7 +320,6 @@ module Phronomy
|
|
|
315
320
|
end
|
|
316
321
|
|
|
317
322
|
submit_workflow_load(
|
|
318
|
-
runtime,
|
|
319
323
|
repository,
|
|
320
324
|
request.workflow_instance_id,
|
|
321
325
|
StartLoadReady,
|
|
@@ -323,7 +327,7 @@ module Phronomy
|
|
|
323
327
|
)
|
|
324
328
|
rescue => error
|
|
325
329
|
if admitted
|
|
326
|
-
|
|
330
|
+
@environment.registry.release_workflow(
|
|
327
331
|
request.workflow_instance_id,
|
|
328
332
|
owner_token: request.owner_token
|
|
329
333
|
)
|
|
@@ -332,10 +336,8 @@ module Phronomy
|
|
|
332
336
|
end
|
|
333
337
|
|
|
334
338
|
def begin_resume_on_event_loop(request)
|
|
335
|
-
runtime = Phronomy::Runtime.instance
|
|
336
|
-
event_loop = runtime.event_loop
|
|
337
339
|
admitted = false
|
|
338
|
-
|
|
340
|
+
@environment.registry.admit_workflow(
|
|
339
341
|
request.workflow_instance_id,
|
|
340
342
|
owner_token: request.owner_token
|
|
341
343
|
)
|
|
@@ -348,10 +350,11 @@ module Phronomy
|
|
|
348
350
|
context: context,
|
|
349
351
|
workflow_instance_id: request.workflow_instance_id,
|
|
350
352
|
owner_token: request.owner_token,
|
|
351
|
-
recursion_limit: Phronomy.
|
|
353
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
352
354
|
repository: nil,
|
|
353
355
|
persist: false,
|
|
354
|
-
expected_revision: nil
|
|
356
|
+
expected_revision: nil,
|
|
357
|
+
cancellation_token: nil
|
|
355
358
|
)
|
|
356
359
|
register_execution(
|
|
357
360
|
execution,
|
|
@@ -363,7 +366,6 @@ module Phronomy
|
|
|
363
366
|
end
|
|
364
367
|
|
|
365
368
|
submit_workflow_load(
|
|
366
|
-
runtime,
|
|
367
369
|
repository,
|
|
368
370
|
request.workflow_instance_id,
|
|
369
371
|
ResumeLoadReady,
|
|
@@ -371,7 +373,7 @@ module Phronomy
|
|
|
371
373
|
)
|
|
372
374
|
rescue => error
|
|
373
375
|
if admitted
|
|
374
|
-
|
|
376
|
+
@environment.registry.release_workflow(
|
|
375
377
|
request.workflow_instance_id,
|
|
376
378
|
owner_token: request.owner_token
|
|
377
379
|
)
|
|
@@ -379,12 +381,12 @@ module Phronomy
|
|
|
379
381
|
fail_task(request.result_task, error)
|
|
380
382
|
end
|
|
381
383
|
|
|
382
|
-
def submit_workflow_load(
|
|
384
|
+
def submit_workflow_load(repository, workflow_instance_id, ready_class, request)
|
|
383
385
|
operation = WorkflowLoadCommand.new(
|
|
384
386
|
repository: repository,
|
|
385
387
|
workflow_instance_id: workflow_instance_id.to_s.freeze
|
|
386
388
|
)
|
|
387
|
-
task =
|
|
389
|
+
task = @environment.submit(on_full: :raise) do
|
|
388
390
|
record = operation.repository.load(operation.workflow_instance_id)
|
|
389
391
|
WorkflowLoadResult.new(
|
|
390
392
|
repository: operation.repository,
|
|
@@ -400,7 +402,7 @@ module Phronomy
|
|
|
400
402
|
error: error
|
|
401
403
|
)
|
|
402
404
|
fail_task(request.result_task, runtime_rejected_error(:load_result)) unless
|
|
403
|
-
post_control(
|
|
405
|
+
post_control(ready)
|
|
404
406
|
end
|
|
405
407
|
nil
|
|
406
408
|
end
|
|
@@ -414,7 +416,7 @@ module Phronomy
|
|
|
414
416
|
|
|
415
417
|
recursion_limit = request.config.fetch(
|
|
416
418
|
:recursion_limit,
|
|
417
|
-
Phronomy.
|
|
419
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
418
420
|
)
|
|
419
421
|
execution = build_new_execution(
|
|
420
422
|
request.input,
|
|
@@ -424,7 +426,8 @@ module Phronomy
|
|
|
424
426
|
repository: ready.result.repository,
|
|
425
427
|
persist: true,
|
|
426
428
|
loaded_snapshot: ready.result.snapshot,
|
|
427
|
-
expected_revision: ready.result.revision
|
|
429
|
+
expected_revision: ready.result.revision,
|
|
430
|
+
cancellation_token: request.config[:cancellation_token]
|
|
428
431
|
)
|
|
429
432
|
register_execution(
|
|
430
433
|
execution,
|
|
@@ -452,10 +455,11 @@ module Phronomy
|
|
|
452
455
|
context: context,
|
|
453
456
|
workflow_instance_id: request.workflow_instance_id,
|
|
454
457
|
owner_token: request.owner_token,
|
|
455
|
-
recursion_limit: Phronomy.
|
|
458
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
456
459
|
repository: ready.result.repository,
|
|
457
460
|
persist: true,
|
|
458
|
-
expected_revision: expected_revision
|
|
461
|
+
expected_revision: expected_revision,
|
|
462
|
+
cancellation_token: nil
|
|
459
463
|
)
|
|
460
464
|
register_execution(
|
|
461
465
|
execution,
|
|
@@ -475,8 +479,11 @@ module Phronomy
|
|
|
475
479
|
repository:,
|
|
476
480
|
persist:,
|
|
477
481
|
loaded_snapshot:,
|
|
478
|
-
expected_revision
|
|
482
|
+
expected_revision:,
|
|
483
|
+
cancellation_token: nil
|
|
479
484
|
)
|
|
485
|
+
stored_phase = loaded_snapshot && (loaded_snapshot[:phase] || loaded_snapshot["phase"])
|
|
486
|
+
reject_task_resume!(stored_phase&.to_sym)
|
|
480
487
|
stored_fields = loaded_snapshot &&
|
|
481
488
|
(loaded_snapshot[:fields] || loaded_snapshot["fields"])
|
|
482
489
|
initial_fields = if stored_fields
|
|
@@ -497,7 +504,8 @@ module Phronomy
|
|
|
497
504
|
recursion_limit: recursion_limit,
|
|
498
505
|
repository: repository,
|
|
499
506
|
persist: persist,
|
|
500
|
-
expected_revision: expected_revision
|
|
507
|
+
expected_revision: expected_revision,
|
|
508
|
+
cancellation_token: cancellation_token
|
|
501
509
|
)
|
|
502
510
|
end
|
|
503
511
|
|
|
@@ -508,7 +516,7 @@ module Phronomy
|
|
|
508
516
|
local_snapshot = normalize_snapshot(snapshot_for(state))
|
|
509
517
|
return durable_revision if normalized_durable == local_snapshot
|
|
510
518
|
|
|
511
|
-
raise Phronomy::
|
|
519
|
+
raise Phronomy::Persistence::StateConflictError,
|
|
512
520
|
"Workflow state changed since the supplied halted context for " \
|
|
513
521
|
"workflow_instance_id #{state.workflow_instance_id.inspect}; explicit reload/reconciliation is required"
|
|
514
522
|
end
|
|
@@ -560,8 +568,7 @@ module Phronomy
|
|
|
560
568
|
end
|
|
561
569
|
|
|
562
570
|
def configured_repository
|
|
563
|
-
|
|
564
|
-
persistence&.workflow_states
|
|
571
|
+
@persistence || Phronomy::WorkflowSettings.current.workflow_store
|
|
565
572
|
end
|
|
566
573
|
|
|
567
574
|
def register_execution(
|
|
@@ -571,17 +578,21 @@ module Phronomy
|
|
|
571
578
|
resume_phase: nil,
|
|
572
579
|
stable_observer: nil
|
|
573
580
|
)
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
581
|
+
assert_execution_owner!
|
|
582
|
+
task_execution = unless @task_states.empty?
|
|
583
|
+
WorkflowTaskExecution.new(definitions: @task_states, registry: @environment.registry,
|
|
584
|
+
environment: @environment, owner_token: execution.owner_token, result_task: result_task,
|
|
585
|
+
cancellation_token: execution.cancellation_token)
|
|
586
|
+
end
|
|
577
587
|
session = build_session_for(
|
|
578
588
|
execution: execution,
|
|
579
|
-
runtime: runtime,
|
|
580
589
|
resume_event: resume_event,
|
|
581
590
|
resume_phase: resume_phase,
|
|
582
|
-
stable_observer: stable_observer
|
|
591
|
+
stable_observer: stable_observer,
|
|
592
|
+
task_execution: task_execution
|
|
583
593
|
)
|
|
584
|
-
|
|
594
|
+
@environment.registry.bind_task_execution(task_execution) if task_execution
|
|
595
|
+
@environment.registry.bind_workflow_session(
|
|
585
596
|
execution.workflow_instance_id,
|
|
586
597
|
owner_token: execution.owner_token,
|
|
587
598
|
fsm_session_id: session.id
|
|
@@ -593,15 +604,15 @@ module Phronomy
|
|
|
593
604
|
execution: execution,
|
|
594
605
|
result_task: result_task,
|
|
595
606
|
result: result,
|
|
596
|
-
error: error
|
|
607
|
+
error: error,
|
|
608
|
+
task_execution: task_execution
|
|
597
609
|
)
|
|
598
610
|
end
|
|
599
|
-
|
|
600
|
-
receiver: Phronomy::WorkflowExecutionRegistry.for(event_loop))
|
|
611
|
+
@environment.register_session(session, completion: source_task)
|
|
601
612
|
result_task
|
|
602
613
|
rescue => error
|
|
603
|
-
if
|
|
604
|
-
|
|
614
|
+
if @environment.executing?
|
|
615
|
+
@environment.registry.release_workflow(
|
|
605
616
|
execution.workflow_instance_id,
|
|
606
617
|
owner_token: execution.owner_token
|
|
607
618
|
)
|
|
@@ -611,14 +622,17 @@ module Phronomy
|
|
|
611
622
|
|
|
612
623
|
# Called from source_task completion on EventLoop, after the FSMSession has
|
|
613
624
|
# accepted the durable terminal result (when a durable barrier is required).
|
|
614
|
-
def finalize_execution(execution:, result_task:, result:, error:)
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).release_workflow(
|
|
625
|
+
def finalize_execution(execution:, result_task:, result:, error:, task_execution: nil)
|
|
626
|
+
assert_execution_owner!
|
|
627
|
+
@environment.registry.release_workflow(
|
|
618
628
|
execution.workflow_instance_id,
|
|
619
629
|
owner_token: execution.owner_token
|
|
620
630
|
)
|
|
621
|
-
error ?
|
|
631
|
+
if error && task_execution&.cancelled_error&.equal?(error)
|
|
632
|
+
result_task.cancel!(error)
|
|
633
|
+
else
|
|
634
|
+
error ? fail_task(result_task, error) : complete_task(result_task, result)
|
|
635
|
+
end
|
|
622
636
|
end
|
|
623
637
|
|
|
624
638
|
def begin_terminal_persistence_on_event_loop(
|
|
@@ -627,10 +641,8 @@ module Phronomy
|
|
|
627
641
|
context:,
|
|
628
642
|
event_sink:
|
|
629
643
|
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
assert_event_loop!(event_loop)
|
|
633
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).mark_workflow_admission(
|
|
644
|
+
assert_execution_owner!
|
|
645
|
+
@environment.registry.mark_workflow_admission(
|
|
634
646
|
execution.workflow_instance_id,
|
|
635
647
|
owner_token: execution.owner_token,
|
|
636
648
|
state: :persisting_terminal
|
|
@@ -643,7 +655,7 @@ module Phronomy
|
|
|
643
655
|
snapshot: deep_immutable_copy(snapshot_for(context))
|
|
644
656
|
)
|
|
645
657
|
|
|
646
|
-
task =
|
|
658
|
+
task = @environment.submit(on_full: :raise) do
|
|
647
659
|
persist_terminal_snapshot(operation)
|
|
648
660
|
end
|
|
649
661
|
task.on_complete do |result, operation_error|
|
|
@@ -663,10 +675,10 @@ module Phronomy
|
|
|
663
675
|
revision: revision,
|
|
664
676
|
error: nil
|
|
665
677
|
)
|
|
666
|
-
rescue Phronomy::
|
|
667
|
-
Phronomy::
|
|
668
|
-
Phronomy::
|
|
669
|
-
Phronomy::
|
|
678
|
+
rescue Phronomy::Persistence::ConflictError,
|
|
679
|
+
Phronomy::Persistence::NotFoundError,
|
|
680
|
+
Phronomy::Persistence::SerializationError,
|
|
681
|
+
Phronomy::Persistence::UnsupportedBackendError => error
|
|
670
682
|
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
671
683
|
outcome: :known_failure,
|
|
672
684
|
revision: nil,
|
|
@@ -688,7 +700,7 @@ module Phronomy
|
|
|
688
700
|
end
|
|
689
701
|
accepted = event_sink.post(:workflow_terminal_persistence_result, delivery)
|
|
690
702
|
unless accepted
|
|
691
|
-
Phronomy.
|
|
703
|
+
Phronomy::RuntimeSettings.current.logger&.warn(
|
|
692
704
|
"[Phronomy] EventLoop rejected Workflow terminal persistence result " \
|
|
693
705
|
"for #{execution.workflow_instance_id.inspect}"
|
|
694
706
|
)
|
|
@@ -697,13 +709,13 @@ module Phronomy
|
|
|
697
709
|
|
|
698
710
|
def reconcile_workflow_terminal_f1(operation, original_error)
|
|
699
711
|
record = operation.repository.load(operation.workflow_instance_id)
|
|
700
|
-
case Phronomy::
|
|
712
|
+
case Phronomy::Persistence::SnapshotComparison.compare_revisioned_snapshot(
|
|
701
713
|
record: record,
|
|
702
714
|
expected_pre_revision: operation.expected_revision,
|
|
703
715
|
intended_snapshot: operation.snapshot
|
|
704
716
|
)
|
|
705
717
|
when :post_state
|
|
706
|
-
revision = Phronomy::
|
|
718
|
+
revision = Phronomy::Persistence::SnapshotComparison.fetch_value(record, :revision)
|
|
707
719
|
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
708
720
|
outcome: :success,
|
|
709
721
|
revision: revision,
|
|
@@ -719,7 +731,7 @@ module Phronomy
|
|
|
719
731
|
error: original_error
|
|
720
732
|
)
|
|
721
733
|
else
|
|
722
|
-
conflict = Phronomy::
|
|
734
|
+
conflict = Phronomy::Persistence::StateConflictError.new(
|
|
723
735
|
"Workflow terminal Persistence outcome conflicts with both expected " \
|
|
724
736
|
"pre-state and intended post-state for #{operation.workflow_instance_id.inspect}"
|
|
725
737
|
)
|
|
@@ -738,9 +750,8 @@ module Phronomy
|
|
|
738
750
|
end
|
|
739
751
|
|
|
740
752
|
def release_and_fail(request, error)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).release_workflow(
|
|
753
|
+
assert_execution_owner!
|
|
754
|
+
@environment.registry.release_workflow(
|
|
744
755
|
request.workflow_instance_id,
|
|
745
756
|
owner_token: request.owner_token
|
|
746
757
|
)
|
|
@@ -756,12 +767,12 @@ module Phronomy
|
|
|
756
767
|
|
|
757
768
|
def build_session_for(
|
|
758
769
|
execution:,
|
|
759
|
-
runtime:,
|
|
760
770
|
resume_event: nil,
|
|
761
771
|
resume_phase: nil,
|
|
762
|
-
stable_observer: nil
|
|
772
|
+
stable_observer: nil,
|
|
773
|
+
task_execution: nil
|
|
763
774
|
)
|
|
764
|
-
|
|
775
|
+
@environment.build_session(
|
|
765
776
|
context: execution.context,
|
|
766
777
|
context_metadata: {
|
|
767
778
|
workflow_instance_id: execution.workflow_instance_id
|
|
@@ -774,27 +785,25 @@ module Phronomy
|
|
|
774
785
|
external_events: @external_events,
|
|
775
786
|
phase_machine_class: @phase_machine_class,
|
|
776
787
|
recursion_limit: execution.recursion_limit,
|
|
777
|
-
event_loop: runtime.event_loop,
|
|
778
788
|
resume_event: resume_event,
|
|
779
789
|
resume_phase: resume_phase,
|
|
780
790
|
stable_observer: stable_observer,
|
|
781
|
-
|
|
791
|
+
persist: terminal_persistence_callback(execution),
|
|
792
|
+
task_execution: task_execution
|
|
782
793
|
)
|
|
783
794
|
end
|
|
784
795
|
|
|
785
|
-
def
|
|
796
|
+
def terminal_persistence_callback(execution)
|
|
786
797
|
return unless execution.repository && execution.persist
|
|
787
798
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
)
|
|
799
|
+
->(terminal_type:, context:, event_sink:) {
|
|
800
|
+
begin_terminal_persistence_on_event_loop(
|
|
801
|
+
execution,
|
|
802
|
+
terminal_type: terminal_type,
|
|
803
|
+
context: context,
|
|
804
|
+
event_sink: event_sink
|
|
805
|
+
)
|
|
806
|
+
}
|
|
798
807
|
end
|
|
799
808
|
|
|
800
809
|
def resolve_resume_event(current_phase, event)
|
|
@@ -819,10 +828,14 @@ module Phronomy
|
|
|
819
828
|
"No external event registered for state #{current_phase.inspect}"
|
|
820
829
|
end
|
|
821
830
|
|
|
822
|
-
def
|
|
831
|
+
def reject_task_resume!(phase)
|
|
832
|
+
raise Phronomy::WorkflowTaskResumeError if phase && @task_states.key?(phase)
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
def post_control(command)
|
|
823
836
|
admission = command.is_a?(StartCommand) || command.is_a?(ResumeCommand)
|
|
824
837
|
completion = admission ? command.result_task : command.request.result_task
|
|
825
|
-
|
|
838
|
+
@environment.registry.post(command,
|
|
826
839
|
admission: admission, completion: completion)
|
|
827
840
|
end
|
|
828
841
|
|
|
@@ -832,8 +845,8 @@ module Phronomy
|
|
|
832
845
|
)
|
|
833
846
|
end
|
|
834
847
|
|
|
835
|
-
def
|
|
836
|
-
return if
|
|
848
|
+
def assert_execution_owner!
|
|
849
|
+
return if @environment.executing?
|
|
837
850
|
|
|
838
851
|
raise Phronomy::Error,
|
|
839
852
|
"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
|