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
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Agent
|
|
5
|
+
# Adds input, output, and tool-result filter support to an agent.
|
|
6
|
+
#
|
|
7
|
+
# Filters transform (or block) values at three call sites:
|
|
8
|
+
# - *input* — the raw user input string, before the LLM is called
|
|
9
|
+
# - *output* — the final LLM output string, before it is returned
|
|
10
|
+
# - *tool result* — the return value of each tool call
|
|
11
|
+
#
|
|
12
|
+
# Each filter in the chain receives the value returned by the previous one.
|
|
13
|
+
# A {Phronomy::FilterBlockError} raised inside any filter propagates to the
|
|
14
|
+
# caller.
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
module Filterable
|
|
18
|
+
def self.included(base)
|
|
19
|
+
base.extend(ClassMethods)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Class-level DSL mixed into the including agent class.
|
|
23
|
+
module ClassMethods
|
|
24
|
+
# Registers a filter applied to every invocation's user input.
|
|
25
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
26
|
+
# when a class is given it is instantiated with +.new+.
|
|
27
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
28
|
+
# @return [void]
|
|
29
|
+
# @api public
|
|
30
|
+
def input_filter(filter)
|
|
31
|
+
@_class_input_filters ||= []
|
|
32
|
+
@_class_input_filters << _resolve_filter(filter)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Registers a filter applied to every invocation's final LLM output.
|
|
36
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
37
|
+
# when a class is given it is instantiated with +.new+.
|
|
38
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
39
|
+
# @return [void]
|
|
40
|
+
# @api public
|
|
41
|
+
def output_filter(filter)
|
|
42
|
+
@_class_output_filters ||= []
|
|
43
|
+
@_class_output_filters << _resolve_filter(filter)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Registers a filter applied to every tool result for all tools.
|
|
47
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
48
|
+
# when a class is given it is instantiated with +.new+.
|
|
49
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
50
|
+
# @return [void]
|
|
51
|
+
# @api public
|
|
52
|
+
def tool_result_filter(filter)
|
|
53
|
+
@_class_tool_result_filters ||= []
|
|
54
|
+
@_class_tool_result_filters << _resolve_filter(filter)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [Array<Phronomy::Filter::Base>]
|
|
58
|
+
# @api private
|
|
59
|
+
def _class_input_filters
|
|
60
|
+
@_class_input_filters || []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Array<Phronomy::Filter::Base>]
|
|
64
|
+
# @api private
|
|
65
|
+
def _class_output_filters
|
|
66
|
+
@_class_output_filters || []
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Array<Phronomy::Filter::Base>]
|
|
70
|
+
# @api private
|
|
71
|
+
def _class_tool_result_filters
|
|
72
|
+
@_class_tool_result_filters || []
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Coerce +filter+ to an instance: if a Class is passed, call +.new+;
|
|
78
|
+
# otherwise return the object as-is.
|
|
79
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
80
|
+
# @return [Phronomy::Filter::Base]
|
|
81
|
+
# @api private
|
|
82
|
+
def _resolve_filter(filter)
|
|
83
|
+
filter.is_a?(Class) ? filter.new : filter
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Registers an input filter on this instance.
|
|
88
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
89
|
+
# when a class is given it is instantiated with +.new+.
|
|
90
|
+
# Runs in addition to any class-level input filters.
|
|
91
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
92
|
+
# @return [self]
|
|
93
|
+
# @api public
|
|
94
|
+
def add_input_filter(filter)
|
|
95
|
+
@_instance_input_filters ||= []
|
|
96
|
+
@_instance_input_filters << _resolve_filter(filter)
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Registers an output filter on this instance.
|
|
101
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
102
|
+
# when a class is given it is instantiated with +.new+.
|
|
103
|
+
# Runs in addition to any class-level output filters.
|
|
104
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
105
|
+
# @return [self]
|
|
106
|
+
# @api public
|
|
107
|
+
def add_output_filter(filter)
|
|
108
|
+
@_instance_output_filters ||= []
|
|
109
|
+
@_instance_output_filters << _resolve_filter(filter)
|
|
110
|
+
self
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Registers a tool result filter on this instance.
|
|
114
|
+
#
|
|
115
|
+
# When called with two arguments, the filter is scoped to the given tool
|
|
116
|
+
# class only. When called with one argument, it applies to all tools.
|
|
117
|
+
# Accepts either a {Phronomy::Filter::Base} instance or a subclass;
|
|
118
|
+
# when a class is given it is instantiated with +.new+.
|
|
119
|
+
#
|
|
120
|
+
# @overload add_tool_result_filter(filter)
|
|
121
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>] applied to every tool
|
|
122
|
+
# @overload add_tool_result_filter(tool_class, filter)
|
|
123
|
+
# @param tool_class [Class] scope the filter to this tool
|
|
124
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
125
|
+
# @return [self]
|
|
126
|
+
# @api public
|
|
127
|
+
def add_tool_result_filter(tool_class_or_filter, filter = nil)
|
|
128
|
+
if filter.nil?
|
|
129
|
+
# Single-argument form: apply to all tools.
|
|
130
|
+
@_instance_tool_result_filters ||= []
|
|
131
|
+
@_instance_tool_result_filters << _resolve_filter(tool_class_or_filter)
|
|
132
|
+
else
|
|
133
|
+
# Two-argument form: scoped to one tool class.
|
|
134
|
+
@_scoped_tool_result_filters ||= {}
|
|
135
|
+
(@_scoped_tool_result_filters[tool_class_or_filter] ||= []) << _resolve_filter(filter)
|
|
136
|
+
end
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
# Run input filters (class-level then instance-level).
|
|
143
|
+
# @param input [String, Hash] the raw user input
|
|
144
|
+
# @return [String, Hash] the (possibly transformed) input
|
|
145
|
+
# @api private
|
|
146
|
+
def run_input_filters!(input)
|
|
147
|
+
class_filters = self.class._class_input_filters
|
|
148
|
+
inst_filters = @_instance_input_filters || []
|
|
149
|
+
(class_filters + inst_filters).inject(input) { |val, f| f.call(val) }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Run output filters (class-level then instance-level).
|
|
153
|
+
# @param output [String] the LLM output
|
|
154
|
+
# @return [String] the (possibly transformed) output
|
|
155
|
+
# @api private
|
|
156
|
+
def run_output_filters!(output)
|
|
157
|
+
class_filters = self.class._class_output_filters
|
|
158
|
+
inst_filters = @_instance_output_filters || []
|
|
159
|
+
(class_filters + inst_filters).inject(output) { |val, f| f.call(val) }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Collect all tool-result filters (global + scoped) for a given tool class.
|
|
163
|
+
# @param tool_class [Class]
|
|
164
|
+
# @return [Array<Phronomy::Filter::Base>]
|
|
165
|
+
# @api private
|
|
166
|
+
def _tool_result_filters_for(tool_class)
|
|
167
|
+
global = self.class._class_tool_result_filters + (@_instance_tool_result_filters || [])
|
|
168
|
+
scoped = (@_scoped_tool_result_filters || {})[tool_class] || []
|
|
169
|
+
global + scoped
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Coerce +filter+ to an instance: if a Class is passed, call +.new+;
|
|
173
|
+
# otherwise return the object as-is.
|
|
174
|
+
# @param filter [Phronomy::Filter::Base, Class<Phronomy::Filter::Base>]
|
|
175
|
+
# @return [Phronomy::Filter::Base]
|
|
176
|
+
# @api private
|
|
177
|
+
def _resolve_filter(filter)
|
|
178
|
+
filter.is_a?(Class) ? filter.new : filter
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
module Agent
|
|
5
|
-
class
|
|
5
|
+
class TransferContext
|
|
6
6
|
Provenance = Data.define(
|
|
7
7
|
:origin_agent_id,
|
|
8
8
|
:origin_record_id,
|
|
@@ -59,7 +59,7 @@ module Phronomy
|
|
|
59
59
|
def initialize(**values)
|
|
60
60
|
provenance = values.fetch(:provenance)
|
|
61
61
|
unless provenance.is_a?(Provenance)
|
|
62
|
-
raise ArgumentError, "
|
|
62
|
+
raise ArgumentError, "TransferContext::Item provenance must be Provenance"
|
|
63
63
|
end
|
|
64
64
|
format = (values[:content_format] || :text).to_sym
|
|
65
65
|
unless %i[text json].include?(format)
|
|
@@ -69,11 +69,11 @@ module Phronomy
|
|
|
69
69
|
candidate_category: values.fetch(:candidate_category).to_sym,
|
|
70
70
|
policy_category: values.fetch(:policy_category).to_sym,
|
|
71
71
|
role: values[:role]&.to_sym,
|
|
72
|
-
content: Phronomy::
|
|
72
|
+
content: Phronomy::Values::Immutable.copy(values.fetch(:content)),
|
|
73
73
|
content_format: format,
|
|
74
74
|
tool_call_id: values[:tool_call_id]&.to_s&.freeze,
|
|
75
75
|
provenance: provenance,
|
|
76
|
-
metadata: Phronomy::
|
|
76
|
+
metadata: Phronomy::Values::Immutable.copy(values[:metadata] || {})
|
|
77
77
|
))
|
|
78
78
|
freeze
|
|
79
79
|
end
|
|
@@ -96,7 +96,7 @@ module Phronomy
|
|
|
96
96
|
|
|
97
97
|
def self.from_h(value)
|
|
98
98
|
source = value.transform_keys(&:to_s)
|
|
99
|
-
raise ArgumentError, "
|
|
99
|
+
raise ArgumentError, "TransferContext schema mismatch" unless source.keys.sort == %w[items responsibility]
|
|
100
100
|
new(responsibility: source.fetch("responsibility"), items: source.fetch("items").map do |raw|
|
|
101
101
|
values = raw.transform_keys(&:to_sym)
|
|
102
102
|
values[:provenance] = Provenance.new(**values.fetch(:provenance).transform_keys(&:to_sym))
|
|
@@ -111,7 +111,7 @@ module Phronomy
|
|
|
111
111
|
@items = Array(items).freeze
|
|
112
112
|
raise ArgumentError, "Handoff Context responsibility must not be empty" if @responsibility.strip.empty?
|
|
113
113
|
unless @items.all? { |item| item.is_a?(Item) }
|
|
114
|
-
raise ArgumentError, "Handoff Context items must be
|
|
114
|
+
raise ArgumentError, "Handoff Context items must be TransferContext::Item values"
|
|
115
115
|
end
|
|
116
116
|
freeze
|
|
117
117
|
end
|
|
@@ -2,32 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
module Agent
|
|
5
|
-
class
|
|
5
|
+
class TransferProjection
|
|
6
6
|
CONTROL_CATEGORIES = %i[instruction handoff_responsibility].freeze
|
|
7
7
|
JSON_CATEGORIES = %i[assistant_message tool_message].freeze
|
|
8
8
|
|
|
9
9
|
Identity = Data.define(:agent_id)
|
|
10
|
-
|
|
11
|
-
Snapshot = Data.define(:handoff, :responsibility, :selection_intent)
|
|
12
|
-
private_constant :Identity, :Edge, :Snapshot
|
|
13
|
-
|
|
14
|
-
# A terminal command contains values only, captured on EventLoop.
|
|
15
|
-
def build_terminal(view:, manifest:, persistence:, source_agent_id:)
|
|
16
|
-
request = Snapshot.new(
|
|
17
|
-
handoff: Edge.new(policy: HandoffPolicy.from_h(view.policy), target_agent: Identity.new(agent_id: view.target_agent_id)),
|
|
18
|
-
responsibility: view.responsibility,
|
|
19
|
-
selection_intent: view.selection_intent.transform_keys(&:to_sym)
|
|
20
|
-
)
|
|
21
|
-
build(request: request, manifest: manifest, persistence: persistence,
|
|
22
|
-
source_agent: Identity.new(agent_id: source_agent_id))
|
|
23
|
-
end
|
|
10
|
+
private_constant :Identity
|
|
24
11
|
|
|
25
12
|
def build(request:, manifest:, persistence:, source_agent:)
|
|
26
|
-
unless request.is_a?(
|
|
27
|
-
raise ArgumentError, "request must be
|
|
13
|
+
unless request.is_a?(ControlRequest)
|
|
14
|
+
raise ArgumentError, "request must be an Agent::ControlRequest"
|
|
28
15
|
end
|
|
29
|
-
unless manifest.is_a?(Phronomy::
|
|
30
|
-
raise ArgumentError, "manifest must be an LLMInputManifest"
|
|
16
|
+
unless manifest.is_a?(Phronomy::Context::LLMInputManifest)
|
|
17
|
+
raise ArgumentError, "manifest must be an Phronomy::Context::LLMInputManifest"
|
|
31
18
|
end
|
|
32
19
|
|
|
33
20
|
groups = project_visible_groups(manifest)
|
|
@@ -42,12 +29,12 @@ module Phronomy
|
|
|
42
29
|
policy_category: group.fetch(:policy_category),
|
|
43
30
|
persistence: persistence,
|
|
44
31
|
source_agent: source_agent,
|
|
45
|
-
target_agent: request.
|
|
32
|
+
target_agent: Identity.new(agent_id: request.target_agent_id)
|
|
46
33
|
)
|
|
47
34
|
end
|
|
48
35
|
end
|
|
49
36
|
|
|
50
|
-
|
|
37
|
+
TransferContext.new(
|
|
51
38
|
responsibility: request.responsibility,
|
|
52
39
|
items: items
|
|
53
40
|
)
|
|
@@ -116,7 +103,7 @@ module Phronomy
|
|
|
116
103
|
end
|
|
117
104
|
|
|
118
105
|
# Compatibility for finalized pre-ACS-04 manifests. New manifests use
|
|
119
|
-
# context_policy_conversation_group_id and do not recreate
|
|
106
|
+
# context_policy_conversation_group_id and do not recreate Phronomy::Context::Unit.
|
|
120
107
|
unit_id = segment.metadata["selection_unit_id"] ||
|
|
121
108
|
segment.metadata[:selection_unit_id]
|
|
122
109
|
return "unit:#{unit_id}" if unit_id
|
|
@@ -125,13 +112,7 @@ module Phronomy
|
|
|
125
112
|
end
|
|
126
113
|
|
|
127
114
|
def include_group?(request, category)
|
|
128
|
-
|
|
129
|
-
return true if policy.required?(category)
|
|
130
|
-
return false if policy.forbidden?(category)
|
|
131
|
-
|
|
132
|
-
request.selection_intent.fetch(category) do
|
|
133
|
-
policy.default_include?(category)
|
|
134
|
-
end
|
|
115
|
+
request.selection.fetch(category, false)
|
|
135
116
|
end
|
|
136
117
|
|
|
137
118
|
def materialize_item(segment, policy_category:, persistence:, source_agent:, target_agent:)
|
|
@@ -147,7 +128,7 @@ module Phronomy
|
|
|
147
128
|
target_agent: target_agent
|
|
148
129
|
)
|
|
149
130
|
|
|
150
|
-
|
|
131
|
+
TransferContext::Item.new(
|
|
151
132
|
candidate_category: category,
|
|
152
133
|
policy_category: policy_category,
|
|
153
134
|
role: segment.role,
|
|
@@ -169,7 +150,7 @@ module Phronomy
|
|
|
169
150
|
metadata[:context_policy_content_format]
|
|
170
151
|
if explicit
|
|
171
152
|
format = explicit.to_sym
|
|
172
|
-
unless Phronomy::
|
|
153
|
+
unless Phronomy::Context::ContextPolicyInput::CONTENT_FORMATS.include?(format)
|
|
173
154
|
raise Phronomy::HandoffError,
|
|
174
155
|
"unsupported Context content format in Manifest: #{explicit.inspect}"
|
|
175
156
|
end
|
|
@@ -182,7 +163,7 @@ module Phronomy
|
|
|
182
163
|
def provenance_for(metadata, segment:, source_agent:, target_agent:)
|
|
183
164
|
inherited = metadata["handoff_provenance"]
|
|
184
165
|
if inherited
|
|
185
|
-
base =
|
|
166
|
+
base = TransferContext::Provenance.new(
|
|
186
167
|
origin_agent_id: inherited["origin_agent_id"] || inherited[:origin_agent_id],
|
|
187
168
|
origin_record_id: inherited["origin_record_id"] || inherited[:origin_record_id],
|
|
188
169
|
origin_execution_id: inherited["origin_execution_id"] || inherited[:origin_execution_id],
|
|
@@ -193,7 +174,7 @@ module Phronomy
|
|
|
193
174
|
return base.forwarded_to(target_agent.agent_id)
|
|
194
175
|
end
|
|
195
176
|
|
|
196
|
-
|
|
177
|
+
TransferContext::Provenance.new(
|
|
197
178
|
origin_agent_id: metadata["source_agent_id"] || source_agent.agent_id,
|
|
198
179
|
origin_record_id: metadata["journal_record_id"],
|
|
199
180
|
origin_execution_id: metadata["source_execution_id"],
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
module Phronomy
|
|
4
6
|
module Agent
|
|
5
7
|
class JournalProjection
|
|
8
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
9
|
+
|
|
6
10
|
MESSAGE_KINDS = %i[
|
|
7
11
|
external_message
|
|
8
12
|
assistant_message
|
|
@@ -41,9 +41,9 @@ module Phronomy
|
|
|
41
41
|
ATTRIBUTES.each do |name|
|
|
42
42
|
value = values.fetch(name)
|
|
43
43
|
value = value.to_sym if %i[kind channel role visibility].include?(name) && value
|
|
44
|
-
instance_variable_set("@#{name}", Immutable.copy(value))
|
|
44
|
+
instance_variable_set("@#{name}", Phronomy::Values::Immutable.copy(value))
|
|
45
45
|
end
|
|
46
|
-
Immutable.validate_canonical_json!(metadata, label: "Journal metadata")
|
|
46
|
+
Phronomy::Values::Immutable.validate_canonical_json!(metadata, label: "Journal metadata")
|
|
47
47
|
freeze
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -52,7 +52,7 @@ module Phronomy
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# Current semantic payload representation. Persistence format identity and
|
|
55
|
-
# compatibility validation are owned by Persistence::
|
|
55
|
+
# compatibility validation are owned by Agent::Persistence::Codec.
|
|
56
56
|
def to_h
|
|
57
57
|
ATTRIBUTES.to_h { |name| [name.to_s, public_send(name)] }
|
|
58
58
|
end
|
|
@@ -31,11 +31,11 @@ module Phronomy
|
|
|
31
31
|
ATTRIBUTES.each do |name|
|
|
32
32
|
value = values.fetch(name)
|
|
33
33
|
value = value.to_sym if name == :status
|
|
34
|
-
instance_variable_set("@#{name}", Immutable.copy(value))
|
|
34
|
+
instance_variable_set("@#{name}", Phronomy::Values::Immutable.copy(value))
|
|
35
35
|
end
|
|
36
36
|
raise ArgumentError, "unknown LLM Call status: #{status.inspect}" unless STATUSES.include?(status)
|
|
37
37
|
raise ArgumentError, "LLM Call sequence must be positive" unless sequence.positive?
|
|
38
|
-
Immutable.validate_canonical_json!(metadata, label: "LLM Call metadata")
|
|
38
|
+
Phronomy::Values::Immutable.validate_canonical_json!(metadata, label: "LLM Call metadata")
|
|
39
39
|
freeze
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Agent
|
|
5
|
+
# Materialized knowledge accepted by create(knowledge:) without internal DTOs.
|
|
6
|
+
# @api public
|
|
7
|
+
KnowledgeItem = Data.define(:content, :metadata) do
|
|
8
|
+
def initialize(content:, metadata: {})
|
|
9
|
+
super(content: String(content).dup.freeze, metadata: Phronomy::Values::Immutable.copy(metadata))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
require "time"
|
|
4
6
|
|
|
5
7
|
module Phronomy
|
|
6
8
|
module Agent
|
|
7
9
|
class AgentRoot
|
|
10
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
11
|
+
|
|
8
12
|
LIFECYCLE_STATUSES = %i[idle active suspended closed invalidated].freeze
|
|
9
13
|
|
|
10
14
|
ATTRIBUTES = %i[
|
|
@@ -36,7 +40,7 @@ module Phronomy
|
|
|
36
40
|
ATTRIBUTES.each do |name|
|
|
37
41
|
value = attributes.fetch(name)
|
|
38
42
|
value = value.to_sym if name == :lifecycle_status
|
|
39
|
-
instance_variable_set("@#{name}", Immutable.copy(value))
|
|
43
|
+
instance_variable_set("@#{name}", Phronomy::Values::Immutable.copy(value))
|
|
40
44
|
end
|
|
41
45
|
unless LIFECYCLE_STATUSES.include?(lifecycle_status)
|
|
42
46
|
raise ArgumentError, "unknown Agent lifecycle status: #{lifecycle_status.inspect}"
|
|
@@ -44,7 +48,7 @@ module Phronomy
|
|
|
44
48
|
raise ArgumentError, "agent_revision must be non-negative" if agent_revision.negative?
|
|
45
49
|
raise ArgumentError, "context_revision must be non-negative" if context_revision.negative?
|
|
46
50
|
raise ArgumentError, "journal_position must be non-negative" if journal_position.negative?
|
|
47
|
-
Immutable.validate_canonical_json!(metadata, label: "Agent metadata")
|
|
51
|
+
Phronomy::Values::Immutable.validate_canonical_json!(metadata, label: "Agent metadata")
|
|
48
52
|
freeze
|
|
49
53
|
end
|
|
50
54
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Agent
|
|
5
|
+
# Agent owns this fresh-instance construction contract. Application
|
|
6
|
+
# composition supplies the concrete default once during loading.
|
|
7
|
+
# @api private
|
|
8
|
+
module DefaultPersistence
|
|
9
|
+
FACTORIES = {}
|
|
10
|
+
private_constant :FACTORIES
|
|
11
|
+
|
|
12
|
+
# A private boot binding, not an application extension registry.
|
|
13
|
+
# @api private
|
|
14
|
+
def self.install_factory(factory)
|
|
15
|
+
raise ArgumentError, "factory must respond to call" unless factory.respond_to?(:call)
|
|
16
|
+
|
|
17
|
+
FACTORIES.replace(persistence: factory).freeze
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Invoke only after explicit and configured instances have been excluded.
|
|
22
|
+
# No instance is cached, shared, or installed in global configuration.
|
|
23
|
+
# @api private
|
|
24
|
+
def self.build
|
|
25
|
+
FACTORIES.fetch(:persistence).call
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
|
|
4
|
+
module Agent
|
|
5
5
|
# Process-local authoritative owner registry for mutable Agent instances.
|
|
6
6
|
#
|
|
7
7
|
# This is not a cache. While a Runtime is alive, one agent_id maps to at most
|
|
8
8
|
# one mutable live Agent object. Construction is reserved before durable
|
|
9
9
|
# create/load so concurrent callers cannot materialize independent objects.
|
|
10
|
-
|
|
10
|
+
# @api private
|
|
11
|
+
class OwnershipRegistry
|
|
12
|
+
# Candidates have no side effects. Runtime retains the first registration.
|
|
13
|
+
# Existing instances remain available for lookup and transition completion
|
|
14
|
+
# after admission closes; their own gate rejects new ownership changes.
|
|
15
|
+
def self.current = ExecutionEnvironment.current.ownership
|
|
16
|
+
def self.existing_current = ExecutionEnvironment.current.existing_ownership
|
|
17
|
+
def self.for(environment) = environment.ownership
|
|
18
|
+
def self.existing_for(environment) = environment.existing_ownership
|
|
19
|
+
|
|
11
20
|
Entry = Data.define(:state, :agent, :token)
|
|
12
21
|
private_constant :Entry
|
|
13
22
|
|
|
14
|
-
def initialize(
|
|
15
|
-
@
|
|
23
|
+
def initialize(environment:)
|
|
24
|
+
@environment = environment
|
|
16
25
|
@mutex = Mutex.new
|
|
17
26
|
@condition = ConditionVariable.new
|
|
18
27
|
@entries = {}
|
|
@@ -24,7 +33,7 @@ module Phronomy
|
|
|
24
33
|
token = reserve_create!(key)
|
|
25
34
|
|
|
26
35
|
begin
|
|
27
|
-
agent = yield(@
|
|
36
|
+
agent = yield(@environment)
|
|
28
37
|
rescue Phronomy::AgentAlreadyExistsError,
|
|
29
38
|
Phronomy::Persistence::ConflictError,
|
|
30
39
|
Phronomy::Persistence::NotFoundError,
|
|
@@ -84,7 +93,7 @@ module Phronomy
|
|
|
84
93
|
end
|
|
85
94
|
|
|
86
95
|
begin
|
|
87
|
-
agent = yield(@
|
|
96
|
+
agent = yield(@environment)
|
|
88
97
|
publish_constructed!(
|
|
89
98
|
key,
|
|
90
99
|
token,
|
|
@@ -147,7 +156,7 @@ module Phronomy
|
|
|
147
156
|
end
|
|
148
157
|
@entries[key] = Entry.new(state: :purging, agent: agent, token: token)
|
|
149
158
|
end
|
|
150
|
-
agent.send(:__mark_purging!, @
|
|
159
|
+
agent.send(:__mark_purging!, @environment)
|
|
151
160
|
token
|
|
152
161
|
end
|
|
153
162
|
|
|
@@ -156,10 +165,10 @@ module Phronomy
|
|
|
156
165
|
@mutex.synchronize do
|
|
157
166
|
entry = @entries[key]
|
|
158
167
|
validate_purge_entry!(entry, agent, token, key)
|
|
168
|
+
agent.send(:__mark_purged!, @environment)
|
|
159
169
|
@entries.delete(key)
|
|
160
170
|
@condition.broadcast
|
|
161
171
|
end
|
|
162
|
-
agent.send(:__mark_purged!, @runtime)
|
|
163
172
|
true
|
|
164
173
|
end
|
|
165
174
|
|
|
@@ -169,10 +178,10 @@ module Phronomy
|
|
|
169
178
|
@mutex.synchronize do
|
|
170
179
|
entry = @entries[key]
|
|
171
180
|
validate_purge_entry!(entry, agent, token, key)
|
|
181
|
+
agent.send(:__restore_live_after_purge_abort!, @environment)
|
|
172
182
|
@entries[key] = Entry.new(state: :live, agent: agent, token: nil)
|
|
173
183
|
@condition.broadcast
|
|
174
184
|
end
|
|
175
|
-
agent.send(:__restore_live_after_purge_abort!, @runtime)
|
|
176
185
|
true
|
|
177
186
|
end
|
|
178
187
|
|
|
@@ -183,6 +192,7 @@ module Phronomy
|
|
|
183
192
|
key = normalize_agent_id(agent.agent_id)
|
|
184
193
|
@mutex.synchronize do
|
|
185
194
|
validate_purge_entry!(@entries[key], agent, token, key)
|
|
195
|
+
agent.send(:__mark_ownership_recovery_required!, @environment)
|
|
186
196
|
@entries[key] = Entry.new(
|
|
187
197
|
state: :recovery_required,
|
|
188
198
|
agent: agent,
|
|
@@ -190,7 +200,6 @@ module Phronomy
|
|
|
190
200
|
)
|
|
191
201
|
@condition.broadcast
|
|
192
202
|
end
|
|
193
|
-
agent.send(:__mark_ownership_recovery_required!, @runtime)
|
|
194
203
|
true
|
|
195
204
|
end
|
|
196
205
|
|
|
@@ -204,7 +213,7 @@ module Phronomy
|
|
|
204
213
|
|
|
205
214
|
# Live/recovery-required entries do not prevent Runtime shutdown. Only an
|
|
206
215
|
# ownership transition that is still actively changing state must settle.
|
|
207
|
-
def
|
|
216
|
+
def wait_until_idle(deadline)
|
|
208
217
|
@mutex.synchronize do
|
|
209
218
|
while @entries.values.any? { |entry| %i[constructing purging].include?(entry.state) }
|
|
210
219
|
remaining = deadline - monotonic_now
|
|
@@ -217,7 +226,7 @@ module Phronomy
|
|
|
217
226
|
end
|
|
218
227
|
end
|
|
219
228
|
|
|
220
|
-
def
|
|
229
|
+
def after_runtime_shutdown
|
|
221
230
|
agents = @mutex.synchronize do
|
|
222
231
|
@state = :terminated
|
|
223
232
|
owned = @entries.values.filter_map(&:agent).uniq
|
|
@@ -225,7 +234,7 @@ module Phronomy
|
|
|
225
234
|
@condition.broadcast
|
|
226
235
|
owned
|
|
227
236
|
end
|
|
228
|
-
agents.each { |agent| agent.send(:__release_runtime_owner!, @
|
|
237
|
+
agents.each { |agent| agent.send(:__release_runtime_owner!, @environment) }
|
|
229
238
|
true
|
|
230
239
|
end
|
|
231
240
|
|
|
@@ -253,7 +262,7 @@ module Phronomy
|
|
|
253
262
|
"constructed Agent identity mismatch: reserved #{key.inspect}, got #{agent.agent_id.inspect}"
|
|
254
263
|
end
|
|
255
264
|
|
|
256
|
-
agent.send(:__bind_runtime_owner!, @
|
|
265
|
+
agent.send(:__bind_runtime_owner!, @environment)
|
|
257
266
|
@mutex.synchronize do
|
|
258
267
|
entry = @entries[key]
|
|
259
268
|
unless entry&.state == :constructing && entry.token.equal?(token)
|
|
@@ -268,7 +277,7 @@ module Phronomy
|
|
|
268
277
|
# :nocov:
|
|
269
278
|
if fail_closed
|
|
270
279
|
fail_construction_closed!(key, token, agent: agent)
|
|
271
|
-
agent&.send(:__mark_ownership_recovery_required!, @
|
|
280
|
+
agent&.send(:__mark_ownership_recovery_required!, @environment)
|
|
272
281
|
else
|
|
273
282
|
release_construction!(key, token)
|
|
274
283
|
end
|