phronomy 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +9 -3
- 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/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/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/features.md +8 -3
- data/docs/getting-started.md +9 -6
- 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/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- 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/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +37 -32
- data/lib/phronomy/agent/base.rb +74 -72
- data/lib/phronomy/agent/before_llm_input.rb +64 -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 +44 -23
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
- 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 +18 -116
- 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 +7 -7
- 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/{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/ownership_registry.rb +18 -23
- 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 +10 -9
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
- 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} +1 -1
- 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/configuration/runtime_settings.rb +49 -0
- 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 +202 -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/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 +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/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- 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 +3 -3
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
- 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/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 +58 -42
- 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_coordinator.rb +83 -74
- 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/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 +549 -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 +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/execution/workflow.rb +7 -7
- 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 +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
- data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -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 +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +57 -16
- data/scripts/api_snapshot.rb +35 -15
- 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 -138
- 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 +10 -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 +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} +2 -16
- 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 +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 +318 -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}/execution_cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_timeout_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
|
|
@@ -91,7 +91,8 @@ module Phronomy
|
|
|
91
91
|
@entry_point = entry_point
|
|
92
92
|
@wait_state_names = wait_state_names
|
|
93
93
|
@persistence = persistence
|
|
94
|
-
@
|
|
94
|
+
@environment = WorkflowExecutionEnvironment.current
|
|
95
|
+
@phase_machine_class = @environment.compile_transitions(
|
|
95
96
|
entry_point: @entry_point,
|
|
96
97
|
declared_states: @declared_states,
|
|
97
98
|
wait_state_names: @wait_state_names,
|
|
@@ -99,7 +100,7 @@ module Phronomy
|
|
|
99
100
|
entry_actions: @entry_actions,
|
|
100
101
|
auto_transitions: auto_transitions,
|
|
101
102
|
exit_actions: exit_actions
|
|
102
|
-
)
|
|
103
|
+
)
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
def invoke(input, config: {})
|
|
@@ -153,7 +154,7 @@ module Phronomy
|
|
|
153
154
|
"Valid events: #{@external_events.keys.inspect}"
|
|
154
155
|
end
|
|
155
156
|
|
|
156
|
-
registry =
|
|
157
|
+
registry = @environment.existing_registry
|
|
157
158
|
return false unless registry
|
|
158
159
|
|
|
159
160
|
registry.post_to_workflow(
|
|
@@ -168,8 +169,7 @@ module Phronomy
|
|
|
168
169
|
# progression therefore remain EventLoop-owned.
|
|
169
170
|
# @api private
|
|
170
171
|
def deliver_on_event_loop(command)
|
|
171
|
-
|
|
172
|
-
assert_event_loop!(event_loop)
|
|
172
|
+
assert_execution_owner!
|
|
173
173
|
|
|
174
174
|
case command
|
|
175
175
|
when StartCommand
|
|
@@ -211,7 +211,7 @@ module Phronomy
|
|
|
211
211
|
end
|
|
212
212
|
|
|
213
213
|
def ensure_blocking_call_allowed!(method_name, async_alternative)
|
|
214
|
-
return unless Phronomy::
|
|
214
|
+
return unless Phronomy::WaitPolicy.blocking_forbidden?
|
|
215
215
|
|
|
216
216
|
raise Phronomy::Error,
|
|
217
217
|
"Cannot call Workflow##{method_name} from the EventLoop thread. " \
|
|
@@ -220,7 +220,6 @@ module Phronomy
|
|
|
220
220
|
|
|
221
221
|
def start_new_execution(input, config, stable_observer: nil)
|
|
222
222
|
reject_legacy_workflow_identity_key!(config)
|
|
223
|
-
runtime = Phronomy::Runtime.instance
|
|
224
223
|
result_task = Phronomy::TaskResult.deferred(name: "workflow:preparing")
|
|
225
224
|
explicit_workflow_instance_id = !config[:workflow_instance_id].nil?
|
|
226
225
|
workflow_instance_id = (config[:workflow_instance_id] || SecureRandom.uuid).to_s.freeze
|
|
@@ -242,7 +241,7 @@ module Phronomy
|
|
|
242
241
|
owner_token: Object.new.freeze,
|
|
243
242
|
explicit_workflow_instance_id: explicit_workflow_instance_id
|
|
244
243
|
)
|
|
245
|
-
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(
|
|
244
|
+
fail_task(result_task, runtime_rejected_error(:start)) unless post_control(command)
|
|
246
245
|
result_task
|
|
247
246
|
rescue => error
|
|
248
247
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -250,7 +249,6 @@ module Phronomy
|
|
|
250
249
|
end
|
|
251
250
|
|
|
252
251
|
def start_resume_execution(state, input:, event_name:, current_phase:)
|
|
253
|
-
runtime = Phronomy::Runtime.instance
|
|
254
252
|
workflow_instance_id = state.workflow_instance_id.to_s.freeze
|
|
255
253
|
result_task = Phronomy::TaskResult.deferred(name: "workflow-resume:#{workflow_instance_id}")
|
|
256
254
|
Phronomy::Tracing::Automatic.observe_task(
|
|
@@ -271,7 +269,7 @@ module Phronomy
|
|
|
271
269
|
workflow_instance_id: workflow_instance_id,
|
|
272
270
|
owner_token: Object.new.freeze
|
|
273
271
|
)
|
|
274
|
-
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(
|
|
272
|
+
fail_task(result_task, runtime_rejected_error(:resume)) unless post_control(command)
|
|
275
273
|
result_task
|
|
276
274
|
rescue => error
|
|
277
275
|
fail_task(result_task, error) if defined?(result_task) && result_task
|
|
@@ -279,10 +277,8 @@ module Phronomy
|
|
|
279
277
|
end
|
|
280
278
|
|
|
281
279
|
def begin_start_on_event_loop(request)
|
|
282
|
-
runtime = Phronomy::Runtime.instance
|
|
283
|
-
event_loop = runtime.event_loop
|
|
284
280
|
admitted = false
|
|
285
|
-
|
|
281
|
+
@environment.registry.admit_workflow(
|
|
286
282
|
request.workflow_instance_id,
|
|
287
283
|
owner_token: request.owner_token
|
|
288
284
|
)
|
|
@@ -290,7 +286,7 @@ module Phronomy
|
|
|
290
286
|
|
|
291
287
|
recursion_limit = request.config.fetch(
|
|
292
288
|
:recursion_limit,
|
|
293
|
-
Phronomy.
|
|
289
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
294
290
|
)
|
|
295
291
|
repository = configured_repository
|
|
296
292
|
persist = request.explicit_workflow_instance_id && !repository.nil?
|
|
@@ -315,7 +311,6 @@ module Phronomy
|
|
|
315
311
|
end
|
|
316
312
|
|
|
317
313
|
submit_workflow_load(
|
|
318
|
-
runtime,
|
|
319
314
|
repository,
|
|
320
315
|
request.workflow_instance_id,
|
|
321
316
|
StartLoadReady,
|
|
@@ -323,7 +318,7 @@ module Phronomy
|
|
|
323
318
|
)
|
|
324
319
|
rescue => error
|
|
325
320
|
if admitted
|
|
326
|
-
|
|
321
|
+
@environment.registry.release_workflow(
|
|
327
322
|
request.workflow_instance_id,
|
|
328
323
|
owner_token: request.owner_token
|
|
329
324
|
)
|
|
@@ -332,10 +327,8 @@ module Phronomy
|
|
|
332
327
|
end
|
|
333
328
|
|
|
334
329
|
def begin_resume_on_event_loop(request)
|
|
335
|
-
runtime = Phronomy::Runtime.instance
|
|
336
|
-
event_loop = runtime.event_loop
|
|
337
330
|
admitted = false
|
|
338
|
-
|
|
331
|
+
@environment.registry.admit_workflow(
|
|
339
332
|
request.workflow_instance_id,
|
|
340
333
|
owner_token: request.owner_token
|
|
341
334
|
)
|
|
@@ -348,7 +341,7 @@ module Phronomy
|
|
|
348
341
|
context: context,
|
|
349
342
|
workflow_instance_id: request.workflow_instance_id,
|
|
350
343
|
owner_token: request.owner_token,
|
|
351
|
-
recursion_limit: Phronomy.
|
|
344
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
352
345
|
repository: nil,
|
|
353
346
|
persist: false,
|
|
354
347
|
expected_revision: nil
|
|
@@ -363,7 +356,6 @@ module Phronomy
|
|
|
363
356
|
end
|
|
364
357
|
|
|
365
358
|
submit_workflow_load(
|
|
366
|
-
runtime,
|
|
367
359
|
repository,
|
|
368
360
|
request.workflow_instance_id,
|
|
369
361
|
ResumeLoadReady,
|
|
@@ -371,7 +363,7 @@ module Phronomy
|
|
|
371
363
|
)
|
|
372
364
|
rescue => error
|
|
373
365
|
if admitted
|
|
374
|
-
|
|
366
|
+
@environment.registry.release_workflow(
|
|
375
367
|
request.workflow_instance_id,
|
|
376
368
|
owner_token: request.owner_token
|
|
377
369
|
)
|
|
@@ -379,12 +371,12 @@ module Phronomy
|
|
|
379
371
|
fail_task(request.result_task, error)
|
|
380
372
|
end
|
|
381
373
|
|
|
382
|
-
def submit_workflow_load(
|
|
374
|
+
def submit_workflow_load(repository, workflow_instance_id, ready_class, request)
|
|
383
375
|
operation = WorkflowLoadCommand.new(
|
|
384
376
|
repository: repository,
|
|
385
377
|
workflow_instance_id: workflow_instance_id.to_s.freeze
|
|
386
378
|
)
|
|
387
|
-
task =
|
|
379
|
+
task = @environment.submit(on_full: :raise) do
|
|
388
380
|
record = operation.repository.load(operation.workflow_instance_id)
|
|
389
381
|
WorkflowLoadResult.new(
|
|
390
382
|
repository: operation.repository,
|
|
@@ -400,7 +392,7 @@ module Phronomy
|
|
|
400
392
|
error: error
|
|
401
393
|
)
|
|
402
394
|
fail_task(request.result_task, runtime_rejected_error(:load_result)) unless
|
|
403
|
-
post_control(
|
|
395
|
+
post_control(ready)
|
|
404
396
|
end
|
|
405
397
|
nil
|
|
406
398
|
end
|
|
@@ -414,7 +406,7 @@ module Phronomy
|
|
|
414
406
|
|
|
415
407
|
recursion_limit = request.config.fetch(
|
|
416
408
|
:recursion_limit,
|
|
417
|
-
Phronomy.
|
|
409
|
+
Phronomy::WorkflowSettings.current.recursion_limit
|
|
418
410
|
)
|
|
419
411
|
execution = build_new_execution(
|
|
420
412
|
request.input,
|
|
@@ -452,7 +444,7 @@ module Phronomy
|
|
|
452
444
|
context: context,
|
|
453
445
|
workflow_instance_id: request.workflow_instance_id,
|
|
454
446
|
owner_token: request.owner_token,
|
|
455
|
-
recursion_limit: Phronomy.
|
|
447
|
+
recursion_limit: Phronomy::WorkflowSettings.current.recursion_limit,
|
|
456
448
|
repository: ready.result.repository,
|
|
457
449
|
persist: true,
|
|
458
450
|
expected_revision: expected_revision
|
|
@@ -508,7 +500,7 @@ module Phronomy
|
|
|
508
500
|
local_snapshot = normalize_snapshot(snapshot_for(state))
|
|
509
501
|
return durable_revision if normalized_durable == local_snapshot
|
|
510
502
|
|
|
511
|
-
raise Phronomy::
|
|
503
|
+
raise Phronomy::Persistence::StateConflictError,
|
|
512
504
|
"Workflow state changed since the supplied halted context for " \
|
|
513
505
|
"workflow_instance_id #{state.workflow_instance_id.inspect}; explicit reload/reconciliation is required"
|
|
514
506
|
end
|
|
@@ -560,8 +552,7 @@ module Phronomy
|
|
|
560
552
|
end
|
|
561
553
|
|
|
562
554
|
def configured_repository
|
|
563
|
-
|
|
564
|
-
persistence&.workflow_states
|
|
555
|
+
@persistence || Phronomy::WorkflowSettings.current.workflow_store
|
|
565
556
|
end
|
|
566
557
|
|
|
567
558
|
def register_execution(
|
|
@@ -571,17 +562,14 @@ module Phronomy
|
|
|
571
562
|
resume_phase: nil,
|
|
572
563
|
stable_observer: nil
|
|
573
564
|
)
|
|
574
|
-
|
|
575
|
-
event_loop = runtime.event_loop
|
|
576
|
-
assert_event_loop!(event_loop)
|
|
565
|
+
assert_execution_owner!
|
|
577
566
|
session = build_session_for(
|
|
578
567
|
execution: execution,
|
|
579
|
-
runtime: runtime,
|
|
580
568
|
resume_event: resume_event,
|
|
581
569
|
resume_phase: resume_phase,
|
|
582
570
|
stable_observer: stable_observer
|
|
583
571
|
)
|
|
584
|
-
|
|
572
|
+
@environment.registry.bind_workflow_session(
|
|
585
573
|
execution.workflow_instance_id,
|
|
586
574
|
owner_token: execution.owner_token,
|
|
587
575
|
fsm_session_id: session.id
|
|
@@ -596,12 +584,11 @@ module Phronomy
|
|
|
596
584
|
error: error
|
|
597
585
|
)
|
|
598
586
|
end
|
|
599
|
-
|
|
600
|
-
receiver: Phronomy::WorkflowExecutionRegistry.for(event_loop))
|
|
587
|
+
@environment.register_session(session, completion: source_task)
|
|
601
588
|
result_task
|
|
602
589
|
rescue => error
|
|
603
|
-
if
|
|
604
|
-
|
|
590
|
+
if @environment.executing?
|
|
591
|
+
@environment.registry.release_workflow(
|
|
605
592
|
execution.workflow_instance_id,
|
|
606
593
|
owner_token: execution.owner_token
|
|
607
594
|
)
|
|
@@ -612,9 +599,8 @@ module Phronomy
|
|
|
612
599
|
# Called from source_task completion on EventLoop, after the FSMSession has
|
|
613
600
|
# accepted the durable terminal result (when a durable barrier is required).
|
|
614
601
|
def finalize_execution(execution:, result_task:, result:, error:)
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).release_workflow(
|
|
602
|
+
assert_execution_owner!
|
|
603
|
+
@environment.registry.release_workflow(
|
|
618
604
|
execution.workflow_instance_id,
|
|
619
605
|
owner_token: execution.owner_token
|
|
620
606
|
)
|
|
@@ -627,10 +613,8 @@ module Phronomy
|
|
|
627
613
|
context:,
|
|
628
614
|
event_sink:
|
|
629
615
|
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
assert_event_loop!(event_loop)
|
|
633
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).mark_workflow_admission(
|
|
616
|
+
assert_execution_owner!
|
|
617
|
+
@environment.registry.mark_workflow_admission(
|
|
634
618
|
execution.workflow_instance_id,
|
|
635
619
|
owner_token: execution.owner_token,
|
|
636
620
|
state: :persisting_terminal
|
|
@@ -643,7 +627,7 @@ module Phronomy
|
|
|
643
627
|
snapshot: deep_immutable_copy(snapshot_for(context))
|
|
644
628
|
)
|
|
645
629
|
|
|
646
|
-
task =
|
|
630
|
+
task = @environment.submit(on_full: :raise) do
|
|
647
631
|
persist_terminal_snapshot(operation)
|
|
648
632
|
end
|
|
649
633
|
task.on_complete do |result, operation_error|
|
|
@@ -663,10 +647,10 @@ module Phronomy
|
|
|
663
647
|
revision: revision,
|
|
664
648
|
error: nil
|
|
665
649
|
)
|
|
666
|
-
rescue Phronomy::
|
|
667
|
-
Phronomy::
|
|
668
|
-
Phronomy::
|
|
669
|
-
Phronomy::
|
|
650
|
+
rescue Phronomy::Persistence::ConflictError,
|
|
651
|
+
Phronomy::Persistence::NotFoundError,
|
|
652
|
+
Phronomy::Persistence::SerializationError,
|
|
653
|
+
Phronomy::Persistence::UnsupportedBackendError => error
|
|
670
654
|
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
671
655
|
outcome: :known_failure,
|
|
672
656
|
revision: nil,
|
|
@@ -688,7 +672,7 @@ module Phronomy
|
|
|
688
672
|
end
|
|
689
673
|
accepted = event_sink.post(:workflow_terminal_persistence_result, delivery)
|
|
690
674
|
unless accepted
|
|
691
|
-
Phronomy.
|
|
675
|
+
Phronomy::RuntimeSettings.current.logger&.warn(
|
|
692
676
|
"[Phronomy] EventLoop rejected Workflow terminal persistence result " \
|
|
693
677
|
"for #{execution.workflow_instance_id.inspect}"
|
|
694
678
|
)
|
|
@@ -697,13 +681,13 @@ module Phronomy
|
|
|
697
681
|
|
|
698
682
|
def reconcile_workflow_terminal_f1(operation, original_error)
|
|
699
683
|
record = operation.repository.load(operation.workflow_instance_id)
|
|
700
|
-
case Phronomy::
|
|
684
|
+
case Phronomy::Persistence::SnapshotComparison.compare_revisioned_snapshot(
|
|
701
685
|
record: record,
|
|
702
686
|
expected_pre_revision: operation.expected_revision,
|
|
703
687
|
intended_snapshot: operation.snapshot
|
|
704
688
|
)
|
|
705
689
|
when :post_state
|
|
706
|
-
revision = Phronomy::
|
|
690
|
+
revision = Phronomy::Persistence::SnapshotComparison.fetch_value(record, :revision)
|
|
707
691
|
Phronomy::WorkflowRunner::WorkflowTerminalPersistenceResult.new(
|
|
708
692
|
outcome: :success,
|
|
709
693
|
revision: revision,
|
|
@@ -719,7 +703,7 @@ module Phronomy
|
|
|
719
703
|
error: original_error
|
|
720
704
|
)
|
|
721
705
|
else
|
|
722
|
-
conflict = Phronomy::
|
|
706
|
+
conflict = Phronomy::Persistence::StateConflictError.new(
|
|
723
707
|
"Workflow terminal Persistence outcome conflicts with both expected " \
|
|
724
708
|
"pre-state and intended post-state for #{operation.workflow_instance_id.inspect}"
|
|
725
709
|
)
|
|
@@ -738,9 +722,8 @@ module Phronomy
|
|
|
738
722
|
end
|
|
739
723
|
|
|
740
724
|
def release_and_fail(request, error)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
Phronomy::WorkflowExecutionRegistry.for(event_loop).release_workflow(
|
|
725
|
+
assert_execution_owner!
|
|
726
|
+
@environment.registry.release_workflow(
|
|
744
727
|
request.workflow_instance_id,
|
|
745
728
|
owner_token: request.owner_token
|
|
746
729
|
)
|
|
@@ -756,12 +739,11 @@ module Phronomy
|
|
|
756
739
|
|
|
757
740
|
def build_session_for(
|
|
758
741
|
execution:,
|
|
759
|
-
runtime:,
|
|
760
742
|
resume_event: nil,
|
|
761
743
|
resume_phase: nil,
|
|
762
744
|
stable_observer: nil
|
|
763
745
|
)
|
|
764
|
-
|
|
746
|
+
@environment.build_session(
|
|
765
747
|
context: execution.context,
|
|
766
748
|
context_metadata: {
|
|
767
749
|
workflow_instance_id: execution.workflow_instance_id
|
|
@@ -774,27 +756,24 @@ module Phronomy
|
|
|
774
756
|
external_events: @external_events,
|
|
775
757
|
phase_machine_class: @phase_machine_class,
|
|
776
758
|
recursion_limit: execution.recursion_limit,
|
|
777
|
-
event_loop: runtime.event_loop,
|
|
778
759
|
resume_event: resume_event,
|
|
779
760
|
resume_phase: resume_phase,
|
|
780
761
|
stable_observer: stable_observer,
|
|
781
|
-
|
|
762
|
+
persist: terminal_persistence_callback(execution)
|
|
782
763
|
)
|
|
783
764
|
end
|
|
784
765
|
|
|
785
|
-
def
|
|
766
|
+
def terminal_persistence_callback(execution)
|
|
786
767
|
return unless execution.repository && execution.persist
|
|
787
768
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
)
|
|
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
|
+
}
|
|
798
777
|
end
|
|
799
778
|
|
|
800
779
|
def resolve_resume_event(current_phase, event)
|
|
@@ -819,10 +798,10 @@ module Phronomy
|
|
|
819
798
|
"No external event registered for state #{current_phase.inspect}"
|
|
820
799
|
end
|
|
821
800
|
|
|
822
|
-
def post_control(
|
|
801
|
+
def post_control(command)
|
|
823
802
|
admission = command.is_a?(StartCommand) || command.is_a?(ResumeCommand)
|
|
824
803
|
completion = admission ? command.result_task : command.request.result_task
|
|
825
|
-
|
|
804
|
+
@environment.registry.post(command,
|
|
826
805
|
admission: admission, completion: completion)
|
|
827
806
|
end
|
|
828
807
|
|
|
@@ -832,8 +811,8 @@ module Phronomy
|
|
|
832
811
|
)
|
|
833
812
|
end
|
|
834
813
|
|
|
835
|
-
def
|
|
836
|
-
return if
|
|
814
|
+
def assert_execution_owner!
|
|
815
|
+
return if @environment.executing?
|
|
837
816
|
|
|
838
817
|
raise Phronomy::Error,
|
|
839
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
|
|
@@ -9,37 +9,43 @@ module Phronomy
|
|
|
9
9
|
def initialize(view) = @view = view
|
|
10
10
|
|
|
11
11
|
def load(workflow_instance_id)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
Phronomy::Persistence::StorageBoundary.call do
|
|
13
|
+
@view.atomic do |bound|
|
|
14
|
+
entry = bound.records(Phronomy::Workflow::Persistence::StorageSchema::STATES).read(workflow_instance_id.to_s)
|
|
15
|
+
entry && decode(entry, workflow_instance_id)
|
|
16
|
+
end
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def save(workflow_instance_id, expected_revision:, snapshot:)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
Phronomy::Persistence::StorageBoundary.call do
|
|
22
|
+
expected = expected_revision.nil? ? nil : Integer(expected_revision)
|
|
23
|
+
revision = expected.nil? ? 1 : expected + 1
|
|
24
|
+
record = Codec.encode_workflow_state(workflow_instance_id: workflow_instance_id,
|
|
25
|
+
workflow_revision: revision, snapshot: snapshot)
|
|
26
|
+
@view.atomic do |bound|
|
|
27
|
+
records = bound.records(Phronomy::Workflow::Persistence::StorageSchema::STATES)
|
|
28
|
+
values = {key: workflow_instance_id.to_s, attributes: {}, record: record}
|
|
29
|
+
entry = if expected.nil?
|
|
30
|
+
records.insert(**values, revision: revision)
|
|
31
|
+
else
|
|
32
|
+
records.replace(**values, expected_revision: expected, next_revision: revision)
|
|
33
|
+
end
|
|
34
|
+
decoded = decode(entry, workflow_instance_id)
|
|
35
|
+
unless decoded.fetch(:revision) == revision
|
|
36
|
+
raise Phronomy::Storage::SerializationError, "backend returned another Workflow revision"
|
|
37
|
+
end
|
|
38
|
+
revision
|
|
34
39
|
end
|
|
35
|
-
|
|
40
|
+
rescue Phronomy::Storage::NotFoundError => error
|
|
41
|
+
raise Phronomy::Storage::ConflictError, error.message
|
|
36
42
|
end
|
|
37
|
-
rescue Phronomy::Storage::NotFoundError => error
|
|
38
|
-
raise Phronomy::Storage::ConflictError, error.message
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
def delete(workflow_instance_id, expected_revision:)
|
|
42
|
-
|
|
46
|
+
Phronomy::Persistence::StorageBoundary.call do
|
|
47
|
+
@view.records(Phronomy::Workflow::Persistence::StorageSchema::STATES).delete(key: workflow_instance_id.to_s, expected_revision: Integer(expected_revision))
|
|
48
|
+
end
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
private
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Domain-owned Workflow metadata, loadable without the Workflow runtime.
|
|
5
|
+
# @api private
|
|
6
|
+
class Workflow
|
|
7
|
+
module Persistence
|
|
8
|
+
module StorageSchema
|
|
9
|
+
STATES = Phronomy::Storage::Resource.new(id: "workflow.states", kind: :records)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Connects one compiled Workflow to its owning Runtime. Construction and
|
|
5
|
+
# transition compilation do not start workers or register execution state.
|
|
6
|
+
# @api private
|
|
7
|
+
class WorkflowEngineEnvironment < WorkflowExecutionEnvironment
|
|
8
|
+
def initialize(runtime: Phronomy::Runtime.instance)
|
|
9
|
+
@runtime = runtime
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def registry = WorkflowExecutionRegistry.for(@runtime.event_loop)
|
|
13
|
+
def existing_registry = WorkflowExecutionRegistry.existing_for(@runtime)
|
|
14
|
+
def executing? = @runtime.event_loop.current?
|
|
15
|
+
|
|
16
|
+
def submit(**options, &operation)
|
|
17
|
+
Phronomy::Execution.submit(runtime: @runtime, **options, &operation)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def compile_transitions(**definition)
|
|
21
|
+
WorkflowPhaseMachineBuilder.new(**definition).build
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def build_session(entry_actions:, persist: nil, **options)
|
|
25
|
+
# Preserve nil/scalar results: initial entry must not re-adopt metadata
|
|
26
|
+
# unless the application actually returns a context.
|
|
27
|
+
initial_actions = entry_actions.to_h do |state_name, callbacks|
|
|
28
|
+
[state_name, callbacks.map { |callback| ->(context) { WorkflowActionRules.entry(callback, context, state_name) } }]
|
|
29
|
+
end
|
|
30
|
+
Phronomy::FSMSession.new(**options, entry_actions: initial_actions, event_loop: @runtime.event_loop,
|
|
31
|
+
terminal_policy: persist && WorkflowTerminalPolicy.new(persist: persist))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def register_session(session, completion:)
|
|
35
|
+
@runtime.event_loop.register(session, completion: completion, receiver: registry)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|