phronomy 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +92 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +13 -3
- data/VERIFY.sh +27 -27
- data/benchmark/bench_agent_invoke.rb +26 -47
- data/benchmark/bench_context_assembler.rb +17 -15
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
- data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
- data/docs/architecture/agent-context.md +4 -2
- data/docs/architecture/agent-transition-ownership.md +13 -0
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +9 -3
- data/docs/architecture/context-management.md +31 -1
- data/docs/architecture/context-preparation-steps.md +90 -0
- data/docs/architecture/entry-action-and-team-wording.md +72 -0
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +86 -0
- data/docs/architecture/generator-verifier-ownership.md +111 -0
- data/docs/architecture/multi-agent-handoff.md +11 -4
- data/docs/architecture/persistence-refactoring-plan.md +50 -0
- data/docs/architecture/persistence.md +45 -4
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +343 -0
- data/docs/architecture/remaining-refactoring-plan.md +390 -0
- data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +56 -0
- data/docs/architecture/tracing.md +2 -2
- data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
- data/docs/architecture.md +222 -0
- data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
- data/docs/decisions/032-storage-backend-composition.md +85 -0
- data/docs/decisions/033-domain-persistence-ownership.md +79 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
- data/docs/decisions/036-context-contract-ownership.md +86 -0
- data/docs/decisions/037-common-definition-ownership.md +62 -0
- data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
- data/docs/decisions/040-configuration-default-composition.md +105 -0
- data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
- data/docs/decisions/042-feature-owned-execution-state.md +106 -0
- data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
- data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
- data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
- data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
- data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
- data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
- data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
- data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
- data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
- data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
- data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
- data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
- data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
- data/docs/decisions/058-neutral-storage-primitives.md +83 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +52 -6
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/features.md +16 -5
- data/docs/getting-started.md +11 -8
- data/docs/migrations/0.15.md +5 -0
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
- data/docs/migrations/handoff-runner-multi-agent.md +37 -0
- data/docs/migrations/neutral-storage-spi.md +43 -0
- data/docs/migrations/parallel-tool-chat-removal.md +49 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/shared-state-multi-agent.md +44 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/storage-backend-composition.md +117 -0
- data/docs/migrations/storage-transaction-boundaries.md +74 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/persistence-backends.md +190 -215
- data/docs/runtime-and-concurrency.md +142 -32
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
- data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
- data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
- data/lib/phronomy/agent/api/agent.rb +17 -0
- data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
- data/lib/phronomy/agent/async_event_api.rb +38 -33
- data/lib/phronomy/agent/base.rb +106 -294
- data/lib/phronomy/agent/before_llm_input.rb +64 -0
- data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
- data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
- data/lib/phronomy/agent/context_importer.rb +2 -2
- data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
- data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
- data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
- data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
- data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
- data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
- data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
- data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
- data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
- data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
- data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
- data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +182 -0
- data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
- data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
- data/lib/phronomy/agent/handoff_error.rb +7 -0
- data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
- data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
- data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
- data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
- data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
- data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +338 -0
- data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
- data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
- data/lib/phronomy/agent/persistence/watermark.rb +29 -0
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
- data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
- data/lib/phronomy/agent/saved_context_reader.rb +55 -0
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/state_writer.rb +166 -0
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
- data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
- data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
- data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/common/configuration_error.rb +7 -0
- data/lib/phronomy/common/error.rb +5 -0
- data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
- data/lib/phronomy/common/values/serializable.rb +32 -0
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/storage_schema.rb +12 -0
- data/lib/phronomy/content_store/stored_contents.rb +44 -0
- data/lib/phronomy/context/assembly.rb +202 -0
- data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
- data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
- data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
- data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
- data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
- data/lib/phronomy/engine/event_loop.rb +164 -630
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +9 -0
- data/lib/phronomy/engine/fsm_session.rb +37 -30
- data/lib/phronomy/engine/metrics.rb +28 -0
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +104 -95
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/execution/backpressure_error.rb +7 -0
- data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
- data/lib/phronomy/execution/cancellation_error.rb +7 -0
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
- data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
- data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
- data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
- data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
- data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
- data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
- data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
- data/lib/phronomy/execution/timeout_error.rb +7 -0
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/filter_block_error.rb +14 -0
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
- data/lib/phronomy/generation/generator_verifier.rb +118 -0
- data/lib/phronomy/generation/low_confidence_error.rb +14 -0
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
- data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
- data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
- data/lib/phronomy/multi_agent/team_execution.rb +1 -1
- data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
- data/lib/phronomy/multi_agent/team_root.rb +1 -1
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +107 -0
- data/lib/phronomy/storage/backends/in_memory.rb +157 -0
- data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
- data/lib/phronomy/storage/blobs.rb +31 -0
- data/lib/phronomy/storage/condition.rb +25 -0
- data/lib/phronomy/storage/condition_failed_error.rb +16 -0
- data/lib/phronomy/storage/conflict_error.rb +9 -0
- data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
- data/lib/phronomy/storage/entry.rb +33 -0
- data/lib/phronomy/storage/guard_ref.rb +13 -0
- data/lib/phronomy/storage/not_found_error.rb +9 -0
- data/lib/phronomy/storage/record_codec.rb +177 -0
- data/lib/phronomy/storage/records.rb +61 -0
- data/lib/phronomy/storage/resource.rb +126 -0
- data/lib/phronomy/storage/scope.rb +25 -0
- data/lib/phronomy/storage/serialization_error.rb +9 -0
- data/lib/phronomy/storage/streams.rb +44 -0
- data/lib/phronomy/storage/transaction_error.rb +10 -0
- data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
- data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
- data/lib/phronomy/storage/validation.rb +53 -0
- data/lib/phronomy/storage/view.rb +131 -0
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
- data/lib/phronomy/testing/persistence_contract.rb +4 -0
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +549 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +1 -1
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
- data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
- data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/persistence/codec.rb +153 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
- data/lib/phronomy.rb +97 -98
- data/scripts/api_snapshot.rb +36 -16
- data/scripts/storage_spi_snapshot.rb +36 -0
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent.rbs +14 -139
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +17 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +0 -21
- data/sig/phronomy/handoff.rbs +12 -4
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent.rbs +24 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +3 -185
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/storage/contracts.rbs +160 -0
- data/sig/phronomy/tool.rbs +58 -5
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +1 -1
- data/sig/phronomy.rbs +0 -49
- metadata +462 -130
- data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -507
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
- data/lib/phronomy/agent/handoff_request.rb +0 -45
- data/lib/phronomy/agent/handoff_runner.rb +0 -178
- data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
- data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/recovery_support.rb +0 -504
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
- data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration.rb +0 -59
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/generator_verifier.rb +0 -369
- data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/metrics.rb +0 -26
- data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
- data/lib/phronomy/persistence/durable_codec.rb +0 -706
- data/lib/phronomy/persistence/in_memory.rb +0 -690
- data/lib/phronomy/persistence/repository_facades.rb +0 -535
- data/lib/phronomy/persistence.rb +0 -276
- data/lib/phronomy/recovery.rb +0 -186
- data/lib/phronomy/ruby_llm_patches.rb +0 -24
- data/lib/phronomy/runnable.rb +0 -54
- data/lib/phronomy/token_usage.rb +0 -85
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow_recovery.rb +0 -123
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
- /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
- /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
|
@@ -1,87 +1,156 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "invalid_result_error"
|
|
4
|
+
|
|
3
5
|
module Phronomy
|
|
4
6
|
module VectorStore
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# Phronomy supplies async convenience methods through {AsyncBackend}; blocking
|
|
9
|
-
# backend work is offloaded through the framework-owned bounded OffloadPool.
|
|
10
|
-
#
|
|
7
|
+
# Owns synchronous operations, input validation and the public result shape.
|
|
8
|
+
# Backends implement protected perform_* operations and embedding_dimension.
|
|
9
|
+
# No execution client, SDK or embedding provider is selected by this class.
|
|
11
10
|
# @api public
|
|
12
11
|
class Base
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# @param
|
|
18
|
-
# @param
|
|
19
|
-
# @
|
|
20
|
-
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
12
|
+
# Validate before invoking the backend. Cancellation is checked before the
|
|
13
|
+
# write, never reported after a successful write. No operation is retried.
|
|
14
|
+
# @param id [String]
|
|
15
|
+
# @param embedding [Array<Numeric>]
|
|
16
|
+
# @param metadata [Hash]
|
|
17
|
+
# @param cancellation_token [#raise_if_cancelled!, nil]
|
|
18
|
+
# @return [self]
|
|
21
19
|
# @api public
|
|
22
20
|
def add(id:, embedding:, metadata: {}, cancellation_token: nil)
|
|
23
21
|
cancellation_token&.raise_if_cancelled!
|
|
24
|
-
|
|
22
|
+
validate_id!(id)
|
|
23
|
+
raise ArgumentError, "metadata must be a Hash" unless metadata.is_a?(Hash)
|
|
24
|
+
vector = validate_vector!(embedding)
|
|
25
|
+
perform_add(id: id, embedding: vector, metadata: metadata, cancellation_token: cancellation_token)
|
|
26
|
+
self
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
# Return
|
|
28
|
-
#
|
|
29
|
-
# @param query_embedding
|
|
30
|
-
# @param k
|
|
31
|
-
# @param cancellation_token [
|
|
32
|
-
# @return [Array<Hash>]
|
|
29
|
+
# Return at most k results ordered by descending similarity. Malformed
|
|
30
|
+
# backend output raises InvalidResultError; transport errors propagate.
|
|
31
|
+
# @param query_embedding [Array<Numeric>]
|
|
32
|
+
# @param k [Integer, String] positive integer or its decimal string
|
|
33
|
+
# @param cancellation_token [#raise_if_cancelled!, nil]
|
|
34
|
+
# @return [Array<Hash>]
|
|
33
35
|
# @api public
|
|
34
36
|
def search(query_embedding:, k: 5, cancellation_token: nil)
|
|
35
37
|
cancellation_token&.raise_if_cancelled!
|
|
36
|
-
|
|
38
|
+
limit = validate_k!(k)
|
|
39
|
+
vector = validate_vector!(query_embedding)
|
|
40
|
+
results = perform_search(query_embedding: vector, k: limit, cancellation_token: cancellation_token)
|
|
41
|
+
validate_results!(results, limit)
|
|
42
|
+
results
|
|
37
43
|
end
|
|
38
44
|
|
|
39
|
-
# Remove a
|
|
40
|
-
#
|
|
41
|
-
# @
|
|
45
|
+
# Remove a document; an absent id is a successful no-op.
|
|
46
|
+
# @param id [String]
|
|
47
|
+
# @return [self]
|
|
42
48
|
# @api public
|
|
43
49
|
def remove(id:)
|
|
44
|
-
|
|
50
|
+
validate_id!(id)
|
|
51
|
+
perform_remove(id: id)
|
|
52
|
+
self
|
|
45
53
|
end
|
|
46
54
|
|
|
47
|
-
#
|
|
55
|
+
# Clear documents without changing the configured dimension.
|
|
56
|
+
# @return [self]
|
|
48
57
|
# @api public
|
|
49
58
|
def clear
|
|
50
|
-
|
|
59
|
+
perform_clear
|
|
60
|
+
self
|
|
51
61
|
end
|
|
52
62
|
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
# @return [Integer]
|
|
63
|
+
# @return [Integer] non-negative document count
|
|
56
64
|
# @api public
|
|
57
65
|
def size
|
|
58
|
-
|
|
66
|
+
count = perform_size
|
|
67
|
+
unless count.is_a?(Integer) && count >= 0
|
|
68
|
+
raise InvalidResultError, "size must return a non-negative Integer"
|
|
69
|
+
end
|
|
70
|
+
count
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
protected
|
|
74
|
+
|
|
75
|
+
# @return [Integer, nil] nil delegates dimension enforcement to the backend
|
|
76
|
+
# @api public
|
|
77
|
+
def embedding_dimension
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Storage extension point; inputs have passed common validation.
|
|
82
|
+
# @api public
|
|
83
|
+
def perform_add(id:, embedding:, metadata:, cancellation_token:)
|
|
84
|
+
raise NotImplementedError, "#{self.class}#perform_add is not implemented"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Search extension point; return the documented result hashes in order.
|
|
88
|
+
# @api public
|
|
89
|
+
def perform_search(query_embedding:, k:, cancellation_token:)
|
|
90
|
+
raise NotImplementedError, "#{self.class}#perform_search is not implemented"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @api public
|
|
94
|
+
def perform_remove(id:)
|
|
95
|
+
raise NotImplementedError, "#{self.class}#perform_remove is not implemented"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @api public
|
|
99
|
+
def perform_clear
|
|
100
|
+
raise NotImplementedError, "#{self.class}#perform_clear is not implemented"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @api public
|
|
104
|
+
def perform_size
|
|
105
|
+
raise NotImplementedError, "#{self.class}#perform_size is not implemented"
|
|
59
106
|
end
|
|
60
107
|
|
|
61
108
|
private
|
|
62
109
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def validate_embedding_dimension!(embedding, expected_dimension)
|
|
67
|
-
return unless expected_dimension
|
|
110
|
+
def validate_id!(id)
|
|
111
|
+
raise ArgumentError, "id must be a String" unless id.is_a?(String)
|
|
112
|
+
end
|
|
68
113
|
|
|
69
|
-
|
|
70
|
-
|
|
114
|
+
def finite_real?(value)
|
|
115
|
+
value.is_a?(Numeric) && value.real? && value.finite? && value.to_f.finite?
|
|
116
|
+
end
|
|
71
117
|
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
def validate_vector!(embedding)
|
|
119
|
+
unless embedding.is_a?(Array) && embedding.all? { |value| finite_real?(value) }
|
|
120
|
+
raise ArgumentError, "embedding must be an Array of finite real numbers"
|
|
121
|
+
end
|
|
122
|
+
dimension = embedding_dimension
|
|
123
|
+
if dimension && embedding.size != dimension
|
|
124
|
+
raise ArgumentError, "Embedding dimension mismatch: expected #{dimension}, got #{embedding.size}"
|
|
125
|
+
end
|
|
126
|
+
embedding.map(&:to_f)
|
|
74
127
|
end
|
|
75
128
|
|
|
76
|
-
# Validates that k is a positive integer.
|
|
77
|
-
# Accepts any value accepted by Integer() (e.g. "5"), but raises
|
|
78
|
-
# ArgumentError for non-integer strings, zero, and negative values.
|
|
79
129
|
def validate_k!(k)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
130
|
+
valid = k.is_a?(Integer) || (k.is_a?(String) && k.match?(/\A\+?\d+\z/))
|
|
131
|
+
unless valid
|
|
132
|
+
raise ArgumentError, "k must be a positive integer"
|
|
133
|
+
end
|
|
134
|
+
value = k.is_a?(String) ? Integer(k, 10) : k
|
|
135
|
+
raise ArgumentError, "k must be a positive integer" unless value >= 1
|
|
136
|
+
value
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def validate_results!(results, limit)
|
|
140
|
+
unless results.is_a?(Array) && results.size <= limit
|
|
141
|
+
raise InvalidResultError, "search must return an Array with at most k results"
|
|
142
|
+
end
|
|
143
|
+
previous = Float::INFINITY
|
|
144
|
+
results.each do |result|
|
|
145
|
+
unless result.is_a?(Hash) && result[:id].is_a?(String) &&
|
|
146
|
+
result[:metadata].is_a?(Hash) && finite_real?(result[:score])
|
|
147
|
+
raise InvalidResultError, "search results require a String id, finite score and Hash metadata"
|
|
148
|
+
end
|
|
149
|
+
if result[:score] > previous
|
|
150
|
+
raise InvalidResultError, "search results must be ordered by descending score"
|
|
151
|
+
end
|
|
152
|
+
previous = result[:score]
|
|
153
|
+
end
|
|
85
154
|
end
|
|
86
155
|
end
|
|
87
156
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../common/error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module VectorStore
|
|
7
|
+
# A backend could not produce a valid synchronous result. This includes
|
|
8
|
+
# malformed external responses that must not be replaced with success values.
|
|
9
|
+
# @api public
|
|
10
|
+
class InvalidResultError < Phronomy::Error; end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,23 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
#
|
|
5
|
-
# and
|
|
6
|
-
#
|
|
7
|
-
# Sub-namespaces are auto-loaded by Zeitwerk:
|
|
8
|
-
# Phronomy::VectorStore::Base
|
|
9
|
-
# Phronomy::VectorStore::InMemory
|
|
10
|
-
# Phronomy::VectorStore::Pgvector
|
|
11
|
-
# Phronomy::VectorStore::RedisSearch
|
|
12
|
-
# Phronomy::VectorStore::Embeddings::Base
|
|
13
|
-
# Phronomy::VectorStore::Embeddings::RubyLLMEmbeddings
|
|
14
|
-
# Phronomy::VectorStore::Loader::Base
|
|
15
|
-
# Phronomy::VectorStore::Loader::PlainTextLoader
|
|
16
|
-
# Phronomy::VectorStore::Loader::MarkdownLoader
|
|
17
|
-
# Phronomy::VectorStore::Loader::CsvLoader
|
|
18
|
-
# Phronomy::VectorStore::Splitter::Base
|
|
19
|
-
# Phronomy::VectorStore::Splitter::FixedSizeSplitter
|
|
20
|
-
# Phronomy::VectorStore::Splitter::RecursiveSplitter
|
|
4
|
+
# Synchronous vector search/storage contract, its backends and execution client.
|
|
5
|
+
# Embeddings and Documents are independent Phronomy responsibilities.
|
|
21
6
|
module VectorStore
|
|
22
7
|
end
|
|
23
8
|
end
|
data/lib/phronomy/version.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
require_relative "workflow_runner"
|
|
4
|
-
require_relative "runnable"
|
|
6
|
+
require_relative "../../execution/runnable"
|
|
5
7
|
|
|
6
8
|
module Phronomy
|
|
7
9
|
# StateChart-style Workflow definition DSL.
|
|
8
10
|
class Workflow
|
|
11
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
12
|
+
|
|
9
13
|
include Phronomy::Runnable
|
|
10
14
|
|
|
11
15
|
def self.define(context_class, persistence: nil, &block)
|
|
@@ -63,7 +67,7 @@ module Phronomy
|
|
|
63
67
|
def _apply_invocation_context(config, invocation_context)
|
|
64
68
|
effective = config.merge(invocation_context: invocation_context)
|
|
65
69
|
if effective[:cancellation_token].nil?
|
|
66
|
-
token =
|
|
70
|
+
token = Phronomy::InvocationControls.effective_timeout_token(invocation_context)
|
|
67
71
|
effective = effective.merge(cancellation_token: token) if token
|
|
68
72
|
end
|
|
69
73
|
effective
|
|
@@ -72,8 +76,6 @@ module Phronomy
|
|
|
72
76
|
public
|
|
73
77
|
|
|
74
78
|
class Builder
|
|
75
|
-
FINISH = Phronomy::WorkflowRunner::FINISH
|
|
76
|
-
|
|
77
79
|
def initialize(context_class, persistence: nil)
|
|
78
80
|
@context_class = context_class
|
|
79
81
|
@persistence = persistence
|
|
@@ -119,7 +121,7 @@ module Phronomy
|
|
|
119
121
|
# They may start asynchronous work and register listeners, but returning
|
|
120
122
|
# Phronomy::TaskResult is an error; completion must arrive as a later event.
|
|
121
123
|
def transition(from:, to:, guard: nil, on: nil, action: nil)
|
|
122
|
-
destination =
|
|
124
|
+
destination = to
|
|
123
125
|
@transitions << {
|
|
124
126
|
from: from,
|
|
125
127
|
to: destination,
|
|
@@ -184,7 +186,7 @@ module Phronomy
|
|
|
184
186
|
|
|
185
187
|
undefined_targets = @transitions
|
|
186
188
|
.map { |transition| transition[:to] }
|
|
187
|
-
.reject { |target| target == FINISH } - all_states
|
|
189
|
+
.reject { |target| target == Completion::FINISH } - all_states
|
|
188
190
|
unless undefined_targets.empty?
|
|
189
191
|
raise ArgumentError,
|
|
190
192
|
"Workflow transition(s) reference undefined state(s): " \
|
|
@@ -205,7 +207,7 @@ module Phronomy
|
|
|
205
207
|
current = queue.shift
|
|
206
208
|
@transitions.each do |transition|
|
|
207
209
|
next unless transition[:from] == current
|
|
208
|
-
next if transition[:to] == FINISH
|
|
210
|
+
next if transition[:to] == Completion::FINISH
|
|
209
211
|
next if reachable.include?(transition[:to])
|
|
210
212
|
|
|
211
213
|
reachable.add(transition[:to])
|
|
@@ -220,7 +222,7 @@ module Phronomy
|
|
|
220
222
|
"[Phronomy] Workflow has unreachable state(s): " \
|
|
221
223
|
"#{unreachable.sort.inspect}. These states can never be entered " \
|
|
222
224
|
"from the initial state #{entry_point.inspect}."
|
|
223
|
-
logger = Phronomy.
|
|
225
|
+
logger = Phronomy::RuntimeSettings.current.logger
|
|
224
226
|
logger ? logger.warn(message) : Kernel.warn(message)
|
|
225
227
|
end
|
|
226
228
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Workflow's synchronous callback rules, independent of FSM representation.
|
|
5
|
+
# Guards and transition actions may receive the triggering application event;
|
|
6
|
+
# actions may initiate async work but must not return a TaskResult.
|
|
7
|
+
# @api private
|
|
8
|
+
module WorkflowActionRules
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def allowed?(guard, context, event)
|
|
12
|
+
guard.nil? || call_with_optional_event(guard, context, event)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def transition(callable, context, event, metadata:)
|
|
16
|
+
return context if callable.nil?
|
|
17
|
+
|
|
18
|
+
result = call_with_optional_event(callable, context, event)
|
|
19
|
+
if result.is_a?(Phronomy::TaskResult)
|
|
20
|
+
raise Phronomy::InvalidAsyncTransitionActionError,
|
|
21
|
+
"Transition action " \
|
|
22
|
+
"#{metadata[:from].inspect} --#{metadata[:event].inspect}--> " \
|
|
23
|
+
"#{metadata[:to].inspect} returned Phronomy::TaskResult. " \
|
|
24
|
+
"Start the asynchronous operation, register its callback/listener, " \
|
|
25
|
+
"and return the WorkflowContext or nil."
|
|
26
|
+
end
|
|
27
|
+
workflow_context_result?(result) ? result : context
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def entry(callable, context, state_name)
|
|
31
|
+
result = callable.call(context)
|
|
32
|
+
if result.is_a?(Phronomy::TaskResult)
|
|
33
|
+
raise Phronomy::InvalidAsyncEntryActionError,
|
|
34
|
+
"Entry action for state #{state_name.inspect} returned Phronomy::TaskResult. " \
|
|
35
|
+
"Start the asynchronous operation, register its callback/listener, " \
|
|
36
|
+
"and return the WorkflowContext or nil."
|
|
37
|
+
end
|
|
38
|
+
result
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def apply_entry(callable, context, state_name)
|
|
42
|
+
result = entry(callable, context, state_name)
|
|
43
|
+
workflow_context_result?(result) ? result : context
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def exit(callable, context, state_name)
|
|
47
|
+
result = callable.call(context)
|
|
48
|
+
if result.is_a?(Phronomy::TaskResult)
|
|
49
|
+
raise Phronomy::InvalidAsyncEntryActionError,
|
|
50
|
+
"Exit action for state #{state_name.inspect} returned Phronomy::TaskResult. " \
|
|
51
|
+
"Exit actions are synchronous Run-to-Completion callbacks."
|
|
52
|
+
end
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def call_with_optional_event(callable, context, event)
|
|
57
|
+
parameters = callable.respond_to?(:parameters) ? callable.parameters : callable.method(:call).parameters
|
|
58
|
+
(parameters.length >= 2) ? callable.call(context, event) : callable.call(context)
|
|
59
|
+
end
|
|
60
|
+
private_class_method :call_with_optional_event
|
|
61
|
+
|
|
62
|
+
def workflow_context_result?(result)
|
|
63
|
+
result.respond_to?(:set_graph_metadata)
|
|
64
|
+
end
|
|
65
|
+
private_class_method :workflow_context_result?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
module Phronomy
|
|
4
6
|
# Module for defining Workflow context data.
|
|
5
7
|
#
|
|
@@ -12,6 +14,8 @@ module Phronomy
|
|
|
12
14
|
# evaluation, return a replacement WorkflowContext, or return +:consume+ to
|
|
13
15
|
# discard a stale/unrelated event without firing a transition.
|
|
14
16
|
module WorkflowContext
|
|
17
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
18
|
+
|
|
15
19
|
def self.included(base)
|
|
16
20
|
base.extend(ClassMethods)
|
|
17
21
|
base.instance_variable_set(:@fields, {})
|
|
@@ -134,7 +138,7 @@ module Phronomy
|
|
|
134
138
|
# dispatch thread. All Workflow execution APIs now use that same path; there
|
|
135
139
|
# is no caller-thread synchronous exception.
|
|
136
140
|
def _assert_write_permitted!
|
|
137
|
-
return if Phronomy::
|
|
141
|
+
return if Phronomy::WaitPolicy.blocking_forbidden?
|
|
138
142
|
|
|
139
143
|
raise Phronomy::WorkflowContextOwnershipError,
|
|
140
144
|
"WorkflowContext fields may only be mutated from the EventLoop dispatch " \
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Workflow-owned connection requirements. Progress, admission and durable
|
|
5
|
+
# outcome interpretation remain in Workflow; composition selects transport.
|
|
6
|
+
# @api private
|
|
7
|
+
class WorkflowExecutionEnvironment
|
|
8
|
+
class << self
|
|
9
|
+
def install_provider(provider)
|
|
10
|
+
raise ArgumentError, "Workflow execution provider must be callable" unless provider.respond_to?(:call)
|
|
11
|
+
@provider = provider
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def current
|
|
15
|
+
@provider&.call || raise(Phronomy::ConfigurationError, "Workflow execution environment has not been configured")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def registry = raise(NotImplementedError)
|
|
20
|
+
def existing_registry = raise(NotImplementedError)
|
|
21
|
+
def executing? = raise(NotImplementedError)
|
|
22
|
+
def submit(**options, &operation) = raise(NotImplementedError)
|
|
23
|
+
def compile_transitions(**definition) = raise(NotImplementedError)
|
|
24
|
+
def build_session(**options) = raise(NotImplementedError)
|
|
25
|
+
def register_session(session, completion:) = raise(NotImplementedError)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Workflow-owned segment admission and routing, mutated only on EventLoop.
|
|
5
|
+
# @api private
|
|
6
|
+
class WorkflowExecutionRegistry < Phronomy::ExecutionReceiver
|
|
7
|
+
# Workflow-owned process-local Workflow execution-segment admission. The
|
|
8
|
+
# owner token is a Runtime coordination capability, not a domain identity or
|
|
9
|
+
# routing identity. fsm_session_id is bound only after durable load/hydration
|
|
10
|
+
# completes and a concrete FSMSession has been constructed.
|
|
11
|
+
WorkflowAdmission = Data.define(
|
|
12
|
+
:workflow_instance_id, :owner_token, :fsm_session_id, :state
|
|
13
|
+
)
|
|
14
|
+
private_constant :WorkflowAdmission
|
|
15
|
+
|
|
16
|
+
def initialize(channel:)
|
|
17
|
+
super
|
|
18
|
+
@workflow_admissions = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def post(command, admission: false, completion: nil)
|
|
22
|
+
post_message(command, admission: admission, completion: completion)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def deliver(command)
|
|
26
|
+
assert_event_loop_thread!
|
|
27
|
+
command.runner.deliver_on_event_loop(command)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def idle?
|
|
31
|
+
!workflow_admission_transition_in_progress_locked?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def session_retired(fsm_session_id, reason:)
|
|
35
|
+
assert_event_loop_thread!
|
|
36
|
+
mark_workflow_recovery_required_for_session(fsm_session_id) if reason == :recovery_required
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def shutdown(error:)
|
|
40
|
+
synchronize { @workflow_admissions.clear }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Reserves one logical Workflow execution segment before durable load or
|
|
44
|
+
# hydration. The owner token is independent from any later FSMSession id.
|
|
45
|
+
# @api private
|
|
46
|
+
def admit_workflow(workflow_instance_id, owner_token:)
|
|
47
|
+
assert_event_loop_thread!
|
|
48
|
+
key = workflow_instance_id.to_s
|
|
49
|
+
raise ArgumentError, "workflow_instance_id must not be empty" if key.empty?
|
|
50
|
+
raise ArgumentError, "owner_token is required" unless owner_token
|
|
51
|
+
|
|
52
|
+
admit do
|
|
53
|
+
if @workflow_admissions.key?(key)
|
|
54
|
+
raise Phronomy::Error,
|
|
55
|
+
"Workflow instance #{key.inspect} already has a live execution segment"
|
|
56
|
+
end
|
|
57
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
58
|
+
workflow_instance_id: key.freeze,
|
|
59
|
+
owner_token: owner_token,
|
|
60
|
+
fsm_session_id: nil,
|
|
61
|
+
state: :admitting
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Binds the concrete routing identity after admission and durable hydration.
|
|
68
|
+
# @api private
|
|
69
|
+
def bind_workflow_session(workflow_instance_id, owner_token:, fsm_session_id:)
|
|
70
|
+
assert_event_loop_thread!
|
|
71
|
+
key = workflow_instance_id.to_s
|
|
72
|
+
fsm_key = fsm_session_id.to_s
|
|
73
|
+
raise ArgumentError, "fsm_session_id must not be empty" if fsm_key.empty?
|
|
74
|
+
|
|
75
|
+
synchronize do
|
|
76
|
+
current = @workflow_admissions.fetch(key) do
|
|
77
|
+
raise Phronomy::Error, "Workflow instance #{key.inspect} has no Runtime admission"
|
|
78
|
+
end
|
|
79
|
+
unless current.owner_token.equal?(owner_token) && current.fsm_session_id.nil?
|
|
80
|
+
raise Phronomy::Error, "stale Workflow admission bind for #{key.inspect}"
|
|
81
|
+
end
|
|
82
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
83
|
+
workflow_instance_id: current.workflow_instance_id,
|
|
84
|
+
owner_token: current.owner_token,
|
|
85
|
+
fsm_session_id: fsm_key.freeze,
|
|
86
|
+
state: :executing
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @api private
|
|
93
|
+
def mark_workflow_admission(workflow_instance_id, owner_token:, state:)
|
|
94
|
+
assert_event_loop_thread!
|
|
95
|
+
key = workflow_instance_id.to_s
|
|
96
|
+
next_state = state.to_sym
|
|
97
|
+
unless %i[executing persisting_terminal recovery_required].include?(next_state)
|
|
98
|
+
raise ArgumentError, "unsupported Workflow admission state: #{next_state.inspect}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
synchronize do
|
|
102
|
+
current = @workflow_admissions.fetch(key) do
|
|
103
|
+
raise Phronomy::Error, "Workflow instance #{key.inspect} has no Runtime admission"
|
|
104
|
+
end
|
|
105
|
+
unless current.owner_token.equal?(owner_token)
|
|
106
|
+
raise Phronomy::Error, "stale Workflow admission update for #{key.inspect}"
|
|
107
|
+
end
|
|
108
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
109
|
+
workflow_instance_id: current.workflow_instance_id,
|
|
110
|
+
owner_token: current.owner_token,
|
|
111
|
+
fsm_session_id: current.fsm_session_id,
|
|
112
|
+
state: next_state
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Owner-aware release. A competing or stale attempt cannot release the
|
|
119
|
+
# current Workflow execution segment.
|
|
120
|
+
# @api private
|
|
121
|
+
def release_workflow(workflow_instance_id, owner_token:)
|
|
122
|
+
assert_event_loop_thread!
|
|
123
|
+
key = workflow_instance_id.to_s
|
|
124
|
+
synchronize do
|
|
125
|
+
current = @workflow_admissions[key]
|
|
126
|
+
next false unless current&.owner_token&.equal?(owner_token)
|
|
127
|
+
|
|
128
|
+
@workflow_admissions.delete(key)
|
|
129
|
+
true
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Read-only diagnostics used by internal tests and routing assertions.
|
|
134
|
+
def workflow_admission_owner(workflow_instance_id)
|
|
135
|
+
synchronize do
|
|
136
|
+
@workflow_admissions[workflow_instance_id.to_s]&.owner_token
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def workflow_admission_fsm_session_id(workflow_instance_id)
|
|
141
|
+
synchronize do
|
|
142
|
+
@workflow_admissions[workflow_instance_id.to_s]&.fsm_session_id
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def workflow_admission_state(workflow_instance_id)
|
|
147
|
+
synchronize do
|
|
148
|
+
@workflow_admissions[workflow_instance_id.to_s]&.state
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def post_to_workflow(workflow_instance_id:, event:, payload: nil)
|
|
153
|
+
route_event(type: event.to_sym, payload: payload) do
|
|
154
|
+
admission = @workflow_admissions[workflow_instance_id.to_s]
|
|
155
|
+
next unless admission&.state == :executing && admission.fsm_session_id
|
|
156
|
+
|
|
157
|
+
admission.fsm_session_id
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def mark_workflow_recovery_required_for_session(fsm_session_id)
|
|
164
|
+
synchronize do
|
|
165
|
+
key, admission = @workflow_admissions.find do |_workflow_instance_id, candidate|
|
|
166
|
+
candidate.fsm_session_id == fsm_session_id.to_s
|
|
167
|
+
end
|
|
168
|
+
return false unless admission
|
|
169
|
+
|
|
170
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
171
|
+
workflow_instance_id: admission.workflow_instance_id,
|
|
172
|
+
owner_token: admission.owner_token,
|
|
173
|
+
fsm_session_id: nil,
|
|
174
|
+
state: :recovery_required
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def workflow_admission_transition_in_progress_locked?
|
|
181
|
+
@workflow_admissions.values.any? do |admission|
|
|
182
|
+
%i[admitting executing persisting_terminal].include?(admission.state)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|