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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Storage
|
|
5
|
+
# Asynchronous execution of a synchronous raw storage backend.
|
|
6
|
+
#
|
|
7
|
+
# A transaction opens, runs and closes on one worker. Return values rather
|
|
8
|
+
# than transaction views: a bound view is closed when the block finishes.
|
|
9
|
+
# Timeout includes queue wait. Timeout/cancellation settles TaskResult but
|
|
10
|
+
# does not interrupt running I/O or guarantee rollback of a started write.
|
|
11
|
+
# Construction starts no Runtime; the default pool is resolved per operation.
|
|
12
|
+
# An explicitly injected pool remains owned by its caller.
|
|
13
|
+
#
|
|
14
|
+
# @api public
|
|
15
|
+
class AsyncClient
|
|
16
|
+
# @param backend [Storage::Backend] synchronous raw SPI 2 backend
|
|
17
|
+
# @param pool [Concurrency::OffloadPool, nil] optional execution pool
|
|
18
|
+
# @api public
|
|
19
|
+
def initialize(backend:, pool: nil)
|
|
20
|
+
Backend.validate_capabilities!(backend)
|
|
21
|
+
@backend = backend
|
|
22
|
+
@pool = pool
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Executes the entire transaction on one worker without waiting for queue
|
|
26
|
+
# capacity. Explicit nested backend transactions retain savepoint semantics.
|
|
27
|
+
#
|
|
28
|
+
# @param cancellation_token [Concurrency::CancellationToken, nil]
|
|
29
|
+
# @param timeout [Numeric, nil] operation-wide submit timeout
|
|
30
|
+
# @yieldparam view [Storage::View] view valid only within this transaction
|
|
31
|
+
# @return [Phronomy::TaskResult] the pool's original completion handle
|
|
32
|
+
# @api public
|
|
33
|
+
def transaction_async(cancellation_token: nil, timeout: nil, &operation)
|
|
34
|
+
raise ArgumentError, "transaction_async requires a block" unless operation
|
|
35
|
+
|
|
36
|
+
Phronomy::Execution.submit(pool: default_pool, timeout: timeout, cancellation_token: cancellation_token, on_full: :raise) do
|
|
37
|
+
@backend.transaction(&operation)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Submit an existing domain-owned synchronous storage unit unchanged.
|
|
42
|
+
# It may already open transactions or perform reads/reconciliation. Do not
|
|
43
|
+
# add a transaction, timeout or cancellation condition around that unit.
|
|
44
|
+
# The owner supplies its current runtime's pool and applies the result.
|
|
45
|
+
#
|
|
46
|
+
# @api private
|
|
47
|
+
def self.submit(pool:, &operation)
|
|
48
|
+
raise ArgumentError, "storage submit requires a block" unless operation
|
|
49
|
+
|
|
50
|
+
Phronomy::Execution.submit(pool: pool, on_full: :raise, &operation)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def default_pool
|
|
56
|
+
@pool
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -30,8 +30,9 @@ module Phronomy
|
|
|
30
30
|
def self.validate_capabilities!(backend)
|
|
31
31
|
capabilities = backend.respond_to?(:capabilities) ? backend.capabilities : {}
|
|
32
32
|
missing = REQUIRED_CAPABILITIES.reject { |key, value| capabilities.is_a?(Hash) && capabilities[key] == value }
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
missing_methods = %i[view transaction transaction_open?].reject { |name| backend.respond_to?(name) }
|
|
34
|
+
unless missing.empty? && missing_methods.empty?
|
|
35
|
+
raise UnsupportedBackendError, "Persistence requires Storage SPI 2: #{(missing.keys + missing_methods).join(", ")}"
|
|
35
36
|
end
|
|
36
37
|
end
|
|
37
38
|
|
|
@@ -40,6 +41,11 @@ module Phronomy
|
|
|
40
41
|
REQUIRED_CAPABILITIES.transform_values { |value| (value == true) ? false : value }.freeze
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
# Whether this synchronous context is already inside a backend transaction.
|
|
45
|
+
# Lets higher-level scopes reject claiming ownership of somebody else's commit.
|
|
46
|
+
# @api public
|
|
47
|
+
def transaction_open? = !current_view.nil?
|
|
48
|
+
|
|
43
49
|
# All declared resources participate in one atomic transaction domain.
|
|
44
50
|
# Record and stream revisions provide compare-and-swap conflict detection.
|
|
45
51
|
# This does not
|
|
@@ -5,6 +5,19 @@ module Phronomy
|
|
|
5
5
|
module Eval
|
|
6
6
|
module Scorer
|
|
7
7
|
class LlmJudge < Base
|
|
8
|
+
CLIENT_FACTORIES = {}
|
|
9
|
+
private_constant :CLIENT_FACTORIES
|
|
10
|
+
|
|
11
|
+
# One-time boot binding, not an application extension registry. The
|
|
12
|
+
# factory runs for each score, after its Request has been prepared.
|
|
13
|
+
# @api private
|
|
14
|
+
def self.install_client_factory(factory)
|
|
15
|
+
raise ArgumentError, "factory must respond to call" unless factory.respond_to?(:call)
|
|
16
|
+
|
|
17
|
+
CLIENT_FACTORIES.replace(client: factory).freeze
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
8
21
|
DEFAULT_PROMPT = <<~PROMPT
|
|
9
22
|
You are an impartial judge evaluating the quality of an AI assistant response.
|
|
10
23
|
Rate the response on a scale from 0.0 (completely wrong or unhelpful) to 1.0 (perfect).
|
|
@@ -32,9 +45,12 @@ module Phronomy
|
|
|
32
45
|
expected: expected.to_s,
|
|
33
46
|
actual: actual.to_s
|
|
34
47
|
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
request = Phronomy::LLMAdapter::Request.new(
|
|
49
|
+
model_config: {"model" => @model, "provider" => @provider&.to_s,
|
|
50
|
+
"assume_model_exists" => @assume_model_exists}.compact,
|
|
51
|
+
message: prompt
|
|
52
|
+
)
|
|
53
|
+
response = CLIENT_FACTORIES.fetch(:client).call.complete_async(request).wait_result
|
|
38
54
|
response.content.to_s.strip.scan(/-?\d+\.?\d*/).first.to_f.clamp(0.0, 1.0)
|
|
39
55
|
rescue => error
|
|
40
56
|
raise if @raise_on_error
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RSpec.shared_examples "a persistence content store" do
|
|
4
|
-
let(:content_store) {
|
|
4
|
+
let(:content_store) { stores.agent.contents }
|
|
5
5
|
|
|
6
6
|
it "returns the same content_id for the same bytes" do
|
|
7
7
|
first = content_store.put("same".b, canonicalization_version: 1)
|
|
@@ -21,7 +21,7 @@ RSpec.shared_examples "a persistence content store" do
|
|
|
21
21
|
it "raises NotFoundError for a missing content_id" do
|
|
22
22
|
expect do
|
|
23
23
|
content_store.fetch("sha256:#{"0" * 64}")
|
|
24
|
-
end.to raise_error(Phronomy::
|
|
24
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it "isolates durable bytes from mutation of fetched values" do
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
5
|
RSpec.shared_examples "a Journal repository" do
|
|
6
|
-
let(:journal_repository) {
|
|
6
|
+
let(:journal_repository) { stores.agent.journals }
|
|
7
7
|
let(:journal_agent_root) do
|
|
8
8
|
Phronomy::Agent::AgentRoot.create(
|
|
9
9
|
agent_id: "journal-agent-#{SecureRandom.uuid}",
|
|
@@ -25,7 +25,7 @@ RSpec.shared_examples "a Journal repository" do
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
before do
|
|
28
|
-
|
|
28
|
+
stores.agent.agents.create(journal_agent_root)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "appends records at the expected position and assigns durable sequences" do
|
|
@@ -51,7 +51,7 @@ RSpec.shared_examples "a Journal repository" do
|
|
|
51
51
|
expected_position: 1,
|
|
52
52
|
records: [record]
|
|
53
53
|
)
|
|
54
|
-
end.to raise_error(Phronomy::
|
|
54
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it "rejects a duplicate record_id already present in the Journal" do
|
|
@@ -76,7 +76,7 @@ RSpec.shared_examples "a Journal repository" do
|
|
|
76
76
|
expected_position: 1,
|
|
77
77
|
records: [duplicate]
|
|
78
78
|
)
|
|
79
|
-
end.to raise_error(Phronomy::
|
|
79
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
it "rejects duplicate record_ids within one append" do
|
|
@@ -94,7 +94,7 @@ RSpec.shared_examples "a Journal repository" do
|
|
|
94
94
|
expected_position: 0,
|
|
95
95
|
records: records
|
|
96
96
|
)
|
|
97
|
-
end.to raise_error(Phronomy::
|
|
97
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
it "rejects records belonging to another Agent" do
|
|
@@ -106,7 +106,7 @@ RSpec.shared_examples "a Journal repository" do
|
|
|
106
106
|
expected_position: 0,
|
|
107
107
|
records: [record]
|
|
108
108
|
)
|
|
109
|
-
end.to raise_error(Phronomy::
|
|
109
|
+
end.to raise_error(Phronomy::Persistence::SerializationError)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
it "reads records in sequence order and supports after/limit" do
|
|
@@ -27,26 +27,25 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
27
27
|
|
|
28
28
|
it "advertises every required capability" do
|
|
29
29
|
Phronomy::Storage::Backend::REQUIRED_CAPABILITIES.each do |name, required_value|
|
|
30
|
-
expect(
|
|
30
|
+
expect(stores.coordinator.backend.capabilities[name]).to eq(required_value)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
it "
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
:contents,
|
|
38
|
-
:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
:
|
|
42
|
-
:
|
|
43
|
-
|
|
44
|
-
)
|
|
34
|
+
it "binds each domain to its own record protocol in one common scope" do
|
|
35
|
+
stores.coordinator.atomic do |scope|
|
|
36
|
+
stores.agent.participate(scope) do |records|
|
|
37
|
+
expect(records).to respond_to(:contents, :agents, :journals, :executions, :retentions, :cancellations, :assert_agent_watermark!)
|
|
38
|
+
expect(records).not_to respond_to(:teams, :team_executions, :workflow_states)
|
|
39
|
+
end
|
|
40
|
+
stores.multi_agent.participate(scope) do |records|
|
|
41
|
+
expect(records).to respond_to(:contents, :teams, :team_executions, :handoff_states)
|
|
42
|
+
expect(records).not_to respond_to(:agents, :executions, :workflow_states)
|
|
43
|
+
end
|
|
45
44
|
end
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
it "returns the transaction block result" do
|
|
49
|
-
expect(
|
|
48
|
+
expect(stores.agent.transaction { |_tx| :contract_result }).to eq(:contract_result)
|
|
50
49
|
end
|
|
51
50
|
|
|
52
51
|
it "commits changes across durable repositories as one transaction" do
|
|
@@ -55,7 +54,7 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
55
54
|
workflow_id = "workflow-#{SecureRandom.uuid}"
|
|
56
55
|
content_id = nil
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
stores.agent.transaction do |tx, scope|
|
|
59
58
|
content_id = tx.contents.put_text("committed")
|
|
60
59
|
tx.agents.create(root)
|
|
61
60
|
appended = tx.journals.append(
|
|
@@ -73,11 +72,13 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
73
72
|
]
|
|
74
73
|
)
|
|
75
74
|
tx.executions.create_active(execution)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
|
|
76
|
+
workflow.save(
|
|
77
|
+
workflow_id,
|
|
78
|
+
expected_revision: nil,
|
|
79
|
+
snapshot: {fields: {value: "committed"}, phase: "pause"}
|
|
80
|
+
)
|
|
81
|
+
end
|
|
81
82
|
|
|
82
83
|
updated_root = root.with(
|
|
83
84
|
agent_revision: 1,
|
|
@@ -87,12 +88,12 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
87
88
|
tx.agents.save(root.agent_id, expected_revision: 0, root: updated_root)
|
|
88
89
|
end
|
|
89
90
|
|
|
90
|
-
expect(
|
|
91
|
-
expect(
|
|
92
|
-
expect(
|
|
93
|
-
expect(
|
|
91
|
+
expect(stores.agent.contents.exist?(content_id)).to be(true)
|
|
92
|
+
expect(stores.agent.agents.load(root.agent_id).agent_revision).to eq(1)
|
|
93
|
+
expect(stores.agent.journals.head(root.agent_id)).to eq(1)
|
|
94
|
+
expect(stores.agent.executions.load(execution.execution_id).execution_id)
|
|
94
95
|
.to eq(execution.execution_id)
|
|
95
|
-
expect(
|
|
96
|
+
expect(stores.workflow.load(workflow_id)).not_to be_nil
|
|
96
97
|
end
|
|
97
98
|
|
|
98
99
|
it "rolls back all durable repositories when the transaction block raises" do
|
|
@@ -102,7 +103,7 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
102
103
|
content_id = nil
|
|
103
104
|
|
|
104
105
|
expect do
|
|
105
|
-
|
|
106
|
+
stores.agent.transaction do |tx, scope|
|
|
106
107
|
content_id = tx.contents.put_text("temporary-#{SecureRandom.uuid}")
|
|
107
108
|
tx.agents.create(root)
|
|
108
109
|
tx.journals.append(
|
|
@@ -120,32 +121,34 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
120
121
|
]
|
|
121
122
|
)
|
|
122
123
|
tx.executions.create_active(execution)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
|
|
125
|
+
workflow.save(
|
|
126
|
+
workflow_id,
|
|
127
|
+
expected_revision: nil,
|
|
128
|
+
snapshot: {fields: {value: "temporary"}, phase: "pause"}
|
|
129
|
+
)
|
|
130
|
+
end
|
|
128
131
|
raise "rollback-contract"
|
|
129
132
|
end
|
|
130
133
|
end.to raise_error("rollback-contract")
|
|
131
134
|
|
|
132
|
-
expect(
|
|
135
|
+
expect(stores.agent.contents.exist?(content_id)).to be(false)
|
|
133
136
|
expect do
|
|
134
|
-
|
|
135
|
-
end.to raise_error(Phronomy::
|
|
136
|
-
expect(
|
|
137
|
+
stores.agent.agents.load(root.agent_id)
|
|
138
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
139
|
+
expect(stores.agent.journals.head(root.agent_id)).to eq(0)
|
|
137
140
|
expect do
|
|
138
|
-
|
|
139
|
-
end.to raise_error(Phronomy::
|
|
140
|
-
expect(
|
|
141
|
+
stores.agent.executions.load(execution.execution_id)
|
|
142
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
143
|
+
expect(stores.workflow.load(workflow_id)).to be_nil
|
|
141
144
|
end
|
|
142
145
|
|
|
143
146
|
it "accepts the current Agent revision and Journal position watermark" do
|
|
144
147
|
root = backend_agent_root
|
|
145
|
-
|
|
148
|
+
stores.agent.agents.create(root)
|
|
146
149
|
|
|
147
150
|
expect(
|
|
148
|
-
|
|
151
|
+
stores.agent.assert_agent_watermark!(
|
|
149
152
|
agent_id: root.agent_id,
|
|
150
153
|
agent_revision: root.agent_revision,
|
|
151
154
|
journal_position: root.journal_position
|
|
@@ -155,23 +158,23 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
155
158
|
|
|
156
159
|
it "raises ConflictError when the durable Agent revision has advanced" do
|
|
157
160
|
root = backend_agent_root
|
|
158
|
-
|
|
161
|
+
stores.agent.agents.create(root)
|
|
159
162
|
advanced = root.with(agent_revision: 1)
|
|
160
|
-
|
|
163
|
+
stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
|
|
161
164
|
|
|
162
165
|
expect do
|
|
163
|
-
|
|
166
|
+
stores.agent.assert_agent_watermark!(
|
|
164
167
|
agent_id: root.agent_id,
|
|
165
168
|
agent_revision: 0,
|
|
166
169
|
journal_position: 0
|
|
167
170
|
)
|
|
168
|
-
end.to raise_error(Phronomy::
|
|
171
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
169
172
|
end
|
|
170
173
|
|
|
171
174
|
it "raises ConflictError when the durable Journal position has advanced" do
|
|
172
175
|
root = backend_agent_root
|
|
173
|
-
|
|
174
|
-
|
|
176
|
+
stores.agent.agents.create(root)
|
|
177
|
+
stores.agent.journals.append(
|
|
175
178
|
root.agent_id,
|
|
176
179
|
expected_position: 0,
|
|
177
180
|
records: [
|
|
@@ -186,23 +189,23 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
186
189
|
)
|
|
187
190
|
|
|
188
191
|
expect do
|
|
189
|
-
|
|
192
|
+
stores.agent.assert_agent_watermark!(
|
|
190
193
|
agent_id: root.agent_id,
|
|
191
194
|
agent_revision: 0,
|
|
192
195
|
journal_position: 0
|
|
193
196
|
)
|
|
194
|
-
end.to raise_error(Phronomy::
|
|
197
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
195
198
|
end
|
|
196
199
|
|
|
197
200
|
it "rolls back earlier writes when a watermark precondition fails" do
|
|
198
201
|
root = backend_agent_root
|
|
199
|
-
|
|
202
|
+
stores.agent.agents.create(root)
|
|
200
203
|
advanced = root.with(agent_revision: 1)
|
|
201
|
-
|
|
204
|
+
stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
|
|
202
205
|
temporary_content_id = nil
|
|
203
206
|
|
|
204
207
|
expect do
|
|
205
|
-
|
|
208
|
+
stores.agent.transaction do |tx, scope|
|
|
206
209
|
temporary_content_id = tx.contents.put_text(
|
|
207
210
|
"watermark-rollback-#{SecureRandom.uuid}"
|
|
208
211
|
)
|
|
@@ -212,8 +215,8 @@ RSpec.shared_examples "a Persistence backend" do
|
|
|
212
215
|
journal_position: 0
|
|
213
216
|
)
|
|
214
217
|
end
|
|
215
|
-
end.to raise_error(Phronomy::
|
|
218
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
216
219
|
|
|
217
|
-
expect(
|
|
220
|
+
expect(stores.agent.contents.exist?(temporary_content_id)).to be(false)
|
|
218
221
|
end
|
|
219
222
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
5
|
RSpec.shared_examples "a workflow state repository" do
|
|
6
|
-
let(:repository) {
|
|
6
|
+
let(:repository) { stores.workflow }
|
|
7
7
|
|
|
8
8
|
def workflow_contract_value(hash, key)
|
|
9
9
|
hash.key?(key) ? hash[key] : hash[key.to_s]
|
|
@@ -54,7 +54,7 @@ RSpec.shared_examples "a workflow state repository" do
|
|
|
54
54
|
expected_revision: nil,
|
|
55
55
|
snapshot: {fields: {value: 2}, phase: "__end__"}
|
|
56
56
|
)
|
|
57
|
-
end.to raise_error(Phronomy::
|
|
57
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
it "returns a snapshot representation accepted by WorkflowRunner" do
|
|
@@ -111,7 +111,7 @@ RSpec.shared_examples "a workflow state repository" do
|
|
|
111
111
|
|
|
112
112
|
expect do
|
|
113
113
|
repository.delete(workflow_instance_id, expected_revision: 99)
|
|
114
|
-
end.to raise_error(Phronomy::
|
|
114
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
115
115
|
|
|
116
116
|
repository.delete(workflow_instance_id, expected_revision: 1)
|
|
117
117
|
expect(repository.load(workflow_instance_id)).to be_nil
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
5
|
RSpec.shared_examples "an Agent repository" do
|
|
6
|
-
let(:agent_repository) {
|
|
6
|
+
let(:agent_repository) { stores.agent.agents }
|
|
7
7
|
let(:agent_root) do
|
|
8
8
|
Phronomy::Agent::AgentRoot.create(
|
|
9
9
|
agent_id: "contract-agent-#{SecureRandom.uuid}",
|
|
@@ -22,13 +22,13 @@ RSpec.shared_examples "an Agent repository" do
|
|
|
22
22
|
|
|
23
23
|
expect do
|
|
24
24
|
agent_repository.create(agent_root)
|
|
25
|
-
end.to raise_error(Phronomy::
|
|
25
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "raises NotFoundError for a missing Agent" do
|
|
29
29
|
expect do
|
|
30
30
|
agent_repository.load("missing-#{SecureRandom.uuid}")
|
|
31
|
-
end.to raise_error(Phronomy::
|
|
31
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
it "saves only at the expected revision" do
|
|
@@ -54,7 +54,7 @@ RSpec.shared_examples "an Agent repository" do
|
|
|
54
54
|
|
|
55
55
|
expect do
|
|
56
56
|
agent_repository.save(agent_root.agent_id, expected_revision: 0, root: stale)
|
|
57
|
-
end.to raise_error(Phronomy::
|
|
57
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
it "rejects an Agent identity mismatch" do
|
|
@@ -71,7 +71,7 @@ RSpec.shared_examples "an Agent repository" do
|
|
|
71
71
|
expected_revision: 0,
|
|
72
72
|
root: other
|
|
73
73
|
)
|
|
74
|
-
end.to raise_error(Phronomy::
|
|
74
|
+
end.to raise_error(Phronomy::Persistence::SerializationError)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
it "requires revision to advance exactly once" do
|
|
@@ -84,7 +84,7 @@ RSpec.shared_examples "an Agent repository" do
|
|
|
84
84
|
expected_revision: 0,
|
|
85
85
|
root: skipped
|
|
86
86
|
)
|
|
87
|
-
end.to raise_error(Phronomy::
|
|
87
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
it "deletes idempotently" do
|
|
@@ -94,6 +94,6 @@ RSpec.shared_examples "an Agent repository" do
|
|
|
94
94
|
|
|
95
95
|
expect do
|
|
96
96
|
agent_repository.load(agent_root.agent_id)
|
|
97
|
-
end.to raise_error(Phronomy::
|
|
97
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
98
98
|
end
|
|
99
99
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
5
|
RSpec.shared_examples "an Execution repository" do
|
|
6
|
-
let(:execution_repository) {
|
|
6
|
+
let(:execution_repository) { stores.agent.executions }
|
|
7
7
|
let(:execution_agent_root) do
|
|
8
8
|
Phronomy::Agent::AgentRoot.create(
|
|
9
9
|
agent_id: "execution-agent-#{SecureRandom.uuid}",
|
|
@@ -27,7 +27,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
before do
|
|
30
|
-
|
|
30
|
+
stores.agent.agents.create(execution_agent_root)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it "creates and loads an active execution" do
|
|
@@ -40,7 +40,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
40
40
|
it "raises NotFoundError for a missing execution" do
|
|
41
41
|
expect do
|
|
42
42
|
execution_repository.load("missing-#{SecureRandom.uuid}")
|
|
43
|
-
end.to raise_error(Phronomy::
|
|
43
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
it "rejects a duplicate execution_id" do
|
|
@@ -49,7 +49,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
49
49
|
|
|
50
50
|
expect do
|
|
51
51
|
execution_repository.create_active(execution)
|
|
52
|
-
end.to raise_error(Phronomy::
|
|
52
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it "admits at most one active or suspended execution for one Agent" do
|
|
@@ -68,7 +68,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
68
68
|
agent_definition_id: "contract-agent",
|
|
69
69
|
agent_definition_version: 1
|
|
70
70
|
)
|
|
71
|
-
|
|
71
|
+
stores.agent.agents.create(other_root)
|
|
72
72
|
|
|
73
73
|
expect do
|
|
74
74
|
execution_repository.create_active(build_contract_execution(execution_agent_root))
|
|
@@ -107,7 +107,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
107
107
|
expected_revision: 0,
|
|
108
108
|
execution: updated
|
|
109
109
|
)
|
|
110
|
-
end.to raise_error(Phronomy::
|
|
110
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
it "rejects an execution identity mismatch" do
|
|
@@ -118,7 +118,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
118
118
|
agent_definition_id: "contract-agent",
|
|
119
119
|
agent_definition_version: 1
|
|
120
120
|
)
|
|
121
|
-
|
|
121
|
+
stores.agent.agents.create(other_root)
|
|
122
122
|
other = build_contract_execution(other_root).with(
|
|
123
123
|
execution_revision: 1,
|
|
124
124
|
status: :active,
|
|
@@ -131,7 +131,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
131
131
|
expected_revision: 0,
|
|
132
132
|
execution: other
|
|
133
133
|
)
|
|
134
|
-
end.to raise_error(Phronomy::
|
|
134
|
+
end.to raise_error(Phronomy::Persistence::SerializationError)
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
it "requires execution revision to advance exactly once" do
|
|
@@ -149,7 +149,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
149
149
|
expected_revision: 0,
|
|
150
150
|
execution: skipped
|
|
151
151
|
)
|
|
152
|
-
end.to raise_error(Phronomy::
|
|
152
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
153
153
|
end
|
|
154
154
|
|
|
155
155
|
it "lists active executions for one Agent" do
|
|
@@ -179,7 +179,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
179
179
|
|
|
180
180
|
expect do
|
|
181
181
|
execution_repository.load(execution.execution_id)
|
|
182
|
-
end.to raise_error(Phronomy::
|
|
182
|
+
end.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
183
183
|
end
|
|
184
184
|
|
|
185
185
|
it "deletes all executions for one Agent without deleting other Agents' executions" do
|
|
@@ -188,7 +188,7 @@ RSpec.shared_examples "an Execution repository" do
|
|
|
188
188
|
agent_definition_id: "contract-agent",
|
|
189
189
|
agent_definition_version: 1
|
|
190
190
|
)
|
|
191
|
-
|
|
191
|
+
stores.agent.agents.create(other_root)
|
|
192
192
|
own = build_contract_execution(execution_agent_root)
|
|
193
193
|
other = build_contract_execution(other_root)
|
|
194
194
|
execution_repository.create_active(own)
|