phronomy 0.25.0 → 0.27.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/CHANGELOG.md +71 -0
- data/CONTRIBUTING.md +4 -4
- data/README.md +14 -7
- data/VERIFY.sh +27 -27
- data/benchmark/bench_agent_invoke.rb +26 -22
- data/benchmark/bench_context_assembler.rb +4 -5
- data/benchmark/bench_regression.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
- data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
- data/docs/architecture/agent-context.md +5 -3
- data/docs/architecture/agent-transition-ownership.md +89 -0
- data/docs/architecture/before-llm-input.md +6 -0
- data/docs/architecture/context-management.md +30 -0
- data/docs/architecture/context-preparation-steps.md +90 -0
- data/docs/architecture/entry-action-and-team-wording.md +72 -0
- data/docs/architecture/execution-metadata-and-values.md +80 -0
- data/docs/architecture/generator-verifier-ownership.md +111 -0
- data/docs/architecture/multi-agent-handoff.md +8 -2
- data/docs/architecture/persistence-refactoring-plan.md +50 -0
- data/docs/architecture/persistence.md +29 -6
- data/docs/architecture/refactoring-closure.md +334 -0
- data/docs/architecture/remaining-refactoring-plan.md +374 -0
- data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
- data/docs/architecture/tool-schema-recording-gap.md +50 -0
- data/docs/architecture/tracing.md +4 -4
- data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
- data/docs/architecture.md +209 -0
- data/docs/async-composition.md +205 -0
- data/docs/decisions/010-cooperative-first-concurrency.md +23 -23
- data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
- 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/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
- data/docs/decisions/032-storage-backend-composition.md +80 -0
- data/docs/decisions/033-domain-persistence-ownership.md +79 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -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 +131 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
- data/docs/decisions/040-configuration-default-composition.md +94 -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 +100 -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 +151 -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 +78 -0
- data/docs/decisions/README.md +35 -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/features.md +21 -12
- data/docs/getting-started.md +10 -10
- data/docs/migrations/0.15.md +5 -0
- data/docs/migrations/durable-semantic-coordination-v2.md +7 -1
- data/docs/migrations/handoff-runner-multi-agent.md +35 -0
- data/docs/migrations/neutral-storage-spi.md +43 -0
- data/docs/migrations/parallel-tool-chat-removal.md +49 -0
- data/docs/migrations/shared-state-multi-agent.md +44 -0
- data/docs/migrations/storage-backend-composition.md +117 -0
- data/docs/migrations/storage-transaction-boundaries.md +74 -0
- data/docs/persistence-backends.md +162 -204
- data/docs/runtime-and-concurrency.md +205 -60
- data/lib/phronomy/agent/api/agent.rb +17 -0
- data/lib/phronomy/agent/async_event_api.rb +2 -2
- data/lib/phronomy/agent/base.rb +55 -251
- data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
- data/lib/phronomy/agent/context/capability/base.rb +67 -26
- data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
- data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
- data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
- data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
- data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
- data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
- data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
- data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
- data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
- data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
- data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
- data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
- data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
- data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +20 -96
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
- data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +12 -13
- data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
- data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
- data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
- data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
- data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
- data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
- data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
- data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
- data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +22 -73
- data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
- data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
- data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
- 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/{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 -10
- data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
- data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
- data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
- data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
- data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
- data/lib/phronomy/agent/persistence/codec.rb +358 -0
- data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
- data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
- data/lib/phronomy/agent/persistence/queries.rb +61 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
- data/lib/phronomy/agent/persistence/watermark.rb +27 -0
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +36 -41
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
- data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +9 -13
- data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
- data/lib/phronomy/agent/selection/candidate.rb +1 -1
- 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 +90 -0
- data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
- data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
- data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
- data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +2 -2
- 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.rb → configuration/configuration.rb} +14 -5
- data/lib/phronomy/configuration/global_configuration.rb +26 -0
- data/lib/phronomy/content_store/storage_schema.rb +11 -0
- data/lib/phronomy/content_store/stored_contents.rb +43 -0
- data/lib/phronomy/engine/backpressure_error.rb +7 -0
- data/lib/phronomy/{blocking.rb → engine/blocking.rb} +15 -8
- data/lib/phronomy/engine/cancellation_error.rb +7 -0
- data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +29 -16
- data/lib/phronomy/engine/concurrency/operation_binding.rb +43 -0
- data/lib/phronomy/engine/concurrency/physical_completion_task.rb +4 -62
- data/lib/phronomy/engine/concurrency/result_collector.rb +99 -0
- data/lib/phronomy/engine/concurrency/result_composition.rb +145 -0
- data/lib/phronomy/engine/concurrency/subscriptions.rb +68 -0
- data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
- data/lib/phronomy/engine/event_loop.rb +160 -626
- data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
- data/lib/phronomy/engine/execution.rb +229 -0
- data/lib/phronomy/engine/execution_cancellation_error.rb +14 -0
- data/lib/phronomy/engine/execution_receiver.rb +65 -0
- data/lib/phronomy/engine/execution_timeout_error.rb +14 -0
- data/lib/phronomy/engine/fsm_protocol.rb +14 -0
- data/lib/phronomy/engine/fsm_session.rb +38 -31
- data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +3 -1
- data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +3 -1
- data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +3 -1
- data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +13 -1
- data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
- data/lib/phronomy/engine/runtime/timer_queue.rb +11 -0
- data/lib/phronomy/engine/runtime.rb +80 -84
- data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
- data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
- data/lib/phronomy/engine/{task.rb → task_result.rb} +101 -42
- data/lib/phronomy/engine/timeout_error.rb +7 -0
- data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
- data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -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/base.rb +2 -2
- data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
- data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
- data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
- data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
- data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
- data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
- data/lib/phronomy/llm_contract/transport_error.rb +7 -0
- data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +8 -8
- data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
- data/lib/phronomy/multi_agent/orchestrator.rb +36 -68
- data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
- data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
- data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
- data/lib/phronomy/multi_agent/team_execution.rb +1 -1
- data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
- data/lib/phronomy/multi_agent/team_root.rb +1 -1
- data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
- data/lib/phronomy/persistence/api/persistence.rb +140 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
- data/lib/phronomy/persistence_composition/repositories.rb +77 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
- data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
- data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
- data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
- data/lib/phronomy/storage/backend.rb +101 -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/scorer/llm_judge.rb +5 -3
- data/lib/phronomy/testing/fake_clock.rb +13 -9
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
- data/lib/phronomy/testing/persistence_contract.rb +4 -0
- data/lib/phronomy/tool/contract/tool_error.rb +7 -0
- data/lib/phronomy/tools/agent.rb +6 -6
- data/lib/phronomy/vector_store/async_backend.rb +5 -5
- data/lib/phronomy/vector_store/embeddings/base.rb +2 -2
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
- data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
- data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
- data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +126 -75
- data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
- data/lib/phronomy/workflow/persistence/codec.rb +153 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
- data/lib/phronomy/workflow/phase_machine_builder.rb +8 -8
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
- data/lib/phronomy.rb +52 -94
- data/scripts/api_snapshot.rb +4 -2
- data/scripts/storage_spi_snapshot.rb +36 -0
- data/sig/phronomy/agent.rbs +4 -5
- data/sig/phronomy/execution_receiver.rbs +34 -0
- data/sig/phronomy/extensions.rbs +5 -5
- data/sig/phronomy/handoff.rbs +4 -2
- data/sig/phronomy/multi_agent.rbs +19 -3
- data/sig/phronomy/persistence.rbs +7 -91
- data/sig/phronomy/runtime.rbs +34 -7
- data/sig/phronomy/storage.rbs +174 -0
- data/sig/phronomy/tool.rbs +11 -2
- data/sig/phronomy/workflow.rbs +1 -1
- metadata +236 -99
- data/lib/phronomy/agent/execution_coordinator.rb +0 -3138
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
- data/lib/phronomy/agent/recovery_support.rb +0 -504
- data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
- data/lib/phronomy/agent/tool_executor.rb +0 -55
- data/lib/phronomy/generator_verifier.rb +0 -369
- data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
- data/lib/phronomy/multi_agent/fan_out_invocation.rb +0 -137
- data/lib/phronomy/multi_agent/fan_out_session_builder.rb +0 -118
- 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/ruby_llm_patches.rb +0 -24
- data/lib/phronomy/workflow_recovery.rb +0 -123
- /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
- /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
- /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
- /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
- /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
- /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
- /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
- /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
- /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
|
@@ -12,7 +12,7 @@ module Phronomy
|
|
|
12
12
|
# the framework rather than by each backend.
|
|
13
13
|
#
|
|
14
14
|
# A future genuine native-async backend may adapt its completion into a
|
|
15
|
-
# {Phronomy::
|
|
15
|
+
# {Phronomy::TaskResult} without an OffloadPool worker, but native async override is
|
|
16
16
|
# not part of the current backend SPI.
|
|
17
17
|
#
|
|
18
18
|
# @api private
|
|
@@ -24,7 +24,7 @@ module Phronomy
|
|
|
24
24
|
# @param metadata [Hash]
|
|
25
25
|
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
26
26
|
# @param timeout [Numeric, nil]
|
|
27
|
-
# @return [Phronomy::
|
|
27
|
+
# @return [Phronomy::TaskResult]
|
|
28
28
|
# @api public
|
|
29
29
|
def add_async(id:, embedding:, metadata: {}, cancellation_token: nil, timeout: nil)
|
|
30
30
|
Phronomy::Runtime.instance.offload.submit(
|
|
@@ -42,7 +42,7 @@ module Phronomy
|
|
|
42
42
|
# @param k [Integer]
|
|
43
43
|
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
44
44
|
# @param timeout [Numeric, nil]
|
|
45
|
-
# @return [Phronomy::
|
|
45
|
+
# @return [Phronomy::TaskResult]
|
|
46
46
|
# @api public
|
|
47
47
|
def search_async(query_embedding:, k: 5, cancellation_token: nil, timeout: nil)
|
|
48
48
|
Phronomy::Runtime.instance.offload.submit(
|
|
@@ -59,7 +59,7 @@ module Phronomy
|
|
|
59
59
|
# @param id [String]
|
|
60
60
|
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
61
61
|
# @param timeout [Numeric, nil]
|
|
62
|
-
# @return [Phronomy::
|
|
62
|
+
# @return [Phronomy::TaskResult]
|
|
63
63
|
# @api public
|
|
64
64
|
def remove_async(id:, cancellation_token: nil, timeout: nil)
|
|
65
65
|
Phronomy::Runtime.instance.offload.submit(
|
|
@@ -75,7 +75,7 @@ module Phronomy
|
|
|
75
75
|
#
|
|
76
76
|
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
77
77
|
# @param timeout [Numeric, nil]
|
|
78
|
-
# @return [Phronomy::
|
|
78
|
+
# @return [Phronomy::TaskResult]
|
|
79
79
|
# @api public
|
|
80
80
|
def clear_async(cancellation_token: nil, timeout: nil)
|
|
81
81
|
Phronomy::Runtime.instance.offload.submit(
|
|
@@ -7,7 +7,7 @@ module Phronomy
|
|
|
7
7
|
#
|
|
8
8
|
# Concrete implementations override {#embed}. Phronomy owns the async
|
|
9
9
|
# bridge: {#embed_async} routes the synchronous implementation through the
|
|
10
|
-
# bounded OffloadPool and returns a {Phronomy::
|
|
10
|
+
# bounded OffloadPool and returns a {Phronomy::TaskResult}.
|
|
11
11
|
#
|
|
12
12
|
# @api public
|
|
13
13
|
class Base
|
|
@@ -27,7 +27,7 @@ module Phronomy
|
|
|
27
27
|
# @param text [String]
|
|
28
28
|
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
29
29
|
# @param timeout [Numeric, nil] operation-wide submit timeout
|
|
30
|
-
# @return [Phronomy::
|
|
30
|
+
# @return [Phronomy::TaskResult]
|
|
31
31
|
# @api public
|
|
32
32
|
def embed_async(text, cancellation_token = nil, timeout: nil)
|
|
33
33
|
Phronomy::Runtime.instance.offload.submit(
|
data/lib/phronomy/version.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../engine/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
require_relative "workflow_runner"
|
|
4
|
-
require_relative "runnable"
|
|
6
|
+
require_relative "../../engine/runnable"
|
|
5
7
|
|
|
6
8
|
module Phronomy
|
|
7
9
|
# StateChart-style Workflow definition DSL.
|
|
8
10
|
class Workflow
|
|
11
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
12
|
+
|
|
9
13
|
include Phronomy::Runnable
|
|
10
14
|
|
|
11
15
|
def self.define(context_class, persistence: nil, &block)
|
|
@@ -72,8 +76,6 @@ module Phronomy
|
|
|
72
76
|
public
|
|
73
77
|
|
|
74
78
|
class Builder
|
|
75
|
-
FINISH = Phronomy::WorkflowRunner::FINISH
|
|
76
|
-
|
|
77
79
|
def initialize(context_class, persistence: nil)
|
|
78
80
|
@context_class = context_class
|
|
79
81
|
@persistence = persistence
|
|
@@ -93,7 +95,7 @@ module Phronomy
|
|
|
93
95
|
#
|
|
94
96
|
# Entry actions are synchronous Run-to-Completion callbacks. To start
|
|
95
97
|
# asynchronous work, register its listener/callback inside the action and
|
|
96
|
-
# return the context or nil. Returning Phronomy::
|
|
98
|
+
# return the context or nil. Returning Phronomy::TaskResult is an error.
|
|
97
99
|
def state(name, action: nil)
|
|
98
100
|
@declared_states << name
|
|
99
101
|
entry(name, action) if action
|
|
@@ -117,9 +119,9 @@ module Phronomy
|
|
|
117
119
|
# Transition actions are synchronous Run-to-Completion callbacks executed
|
|
118
120
|
# after the source exit callbacks and before the target entry callbacks.
|
|
119
121
|
# They may start asynchronous work and register listeners, but returning
|
|
120
|
-
# Phronomy::
|
|
122
|
+
# Phronomy::TaskResult is an error; completion must arrive as a later event.
|
|
121
123
|
def transition(from:, to:, guard: nil, on: nil, action: nil)
|
|
122
|
-
destination = (to == :__finish__) ? FINISH : to
|
|
124
|
+
destination = (to == :__finish__) ? FSMProtocol::FINISH : to
|
|
123
125
|
@transitions << {
|
|
124
126
|
from: from,
|
|
125
127
|
to: destination,
|
|
@@ -184,7 +186,7 @@ module Phronomy
|
|
|
184
186
|
|
|
185
187
|
undefined_targets = @transitions
|
|
186
188
|
.map { |transition| transition[:to] }
|
|
187
|
-
.reject { |target| target == FINISH } - all_states
|
|
189
|
+
.reject { |target| target == FSMProtocol::FINISH } - all_states
|
|
188
190
|
unless undefined_targets.empty?
|
|
189
191
|
raise ArgumentError,
|
|
190
192
|
"Workflow transition(s) reference undefined state(s): " \
|
|
@@ -205,7 +207,7 @@ module Phronomy
|
|
|
205
207
|
current = queue.shift
|
|
206
208
|
@transitions.each do |transition|
|
|
207
209
|
next unless transition[:from] == current
|
|
208
|
-
next if transition[:to] == FINISH
|
|
210
|
+
next if transition[:to] == FSMProtocol::FINISH
|
|
209
211
|
next if reachable.include?(transition[:to])
|
|
210
212
|
|
|
211
213
|
reachable.add(transition[:to])
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../../engine/concurrency/worker_input_restricted"
|
|
4
|
+
|
|
3
5
|
module Phronomy
|
|
4
6
|
# Module for defining Workflow context data.
|
|
5
7
|
#
|
|
@@ -12,6 +14,8 @@ module Phronomy
|
|
|
12
14
|
# evaluation, return a replacement WorkflowContext, or return +:consume+ to
|
|
13
15
|
# discard a stale/unrelated event without firing a transition.
|
|
14
16
|
module WorkflowContext
|
|
17
|
+
include Phronomy::Concurrency::WorkerInputRestricted
|
|
18
|
+
|
|
15
19
|
def self.included(base)
|
|
16
20
|
base.extend(ClassMethods)
|
|
17
21
|
base.instance_variable_set(:@fields, {})
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Workflow-owned segment admission and routing, mutated only on EventLoop.
|
|
5
|
+
# @api private
|
|
6
|
+
class WorkflowExecutionRegistry < Phronomy::ExecutionReceiver
|
|
7
|
+
# Workflow-owned process-local Workflow execution-segment admission. The
|
|
8
|
+
# owner token is a Runtime coordination capability, not a domain identity or
|
|
9
|
+
# routing identity. fsm_session_id is bound only after durable load/hydration
|
|
10
|
+
# completes and a concrete FSMSession has been constructed.
|
|
11
|
+
WorkflowAdmission = Data.define(
|
|
12
|
+
:workflow_instance_id, :owner_token, :fsm_session_id, :state
|
|
13
|
+
)
|
|
14
|
+
private_constant :WorkflowAdmission
|
|
15
|
+
|
|
16
|
+
def initialize(event_loop:)
|
|
17
|
+
super
|
|
18
|
+
@workflow_admissions = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def post(command, admission: false, completion: nil)
|
|
22
|
+
post_message(command, admission: admission, completion: completion)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def deliver(command)
|
|
26
|
+
assert_event_loop_thread!
|
|
27
|
+
command.runner.deliver_on_event_loop(command)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def idle?
|
|
31
|
+
!workflow_admission_transition_in_progress_locked?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def session_retired(fsm_session_id, reason:)
|
|
35
|
+
assert_event_loop_thread!
|
|
36
|
+
mark_workflow_recovery_required_for_session(fsm_session_id) if reason == :recovery_required
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def shutdown(error:)
|
|
40
|
+
synchronize { @workflow_admissions.clear }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Reserves one logical Workflow execution segment before durable load or
|
|
44
|
+
# hydration. The owner token is independent from any later FSMSession id.
|
|
45
|
+
# @api private
|
|
46
|
+
def admit_workflow(workflow_instance_id, owner_token:)
|
|
47
|
+
assert_event_loop_thread!
|
|
48
|
+
key = workflow_instance_id.to_s
|
|
49
|
+
raise ArgumentError, "workflow_instance_id must not be empty" if key.empty?
|
|
50
|
+
raise ArgumentError, "owner_token is required" unless owner_token
|
|
51
|
+
|
|
52
|
+
admit do
|
|
53
|
+
if @workflow_admissions.key?(key)
|
|
54
|
+
raise Phronomy::Error,
|
|
55
|
+
"Workflow instance #{key.inspect} already has a live execution segment"
|
|
56
|
+
end
|
|
57
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
58
|
+
workflow_instance_id: key.freeze,
|
|
59
|
+
owner_token: owner_token,
|
|
60
|
+
fsm_session_id: nil,
|
|
61
|
+
state: :admitting
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Binds the concrete routing identity after admission and durable hydration.
|
|
68
|
+
# @api private
|
|
69
|
+
def bind_workflow_session(workflow_instance_id, owner_token:, fsm_session_id:)
|
|
70
|
+
assert_event_loop_thread!
|
|
71
|
+
key = workflow_instance_id.to_s
|
|
72
|
+
fsm_key = fsm_session_id.to_s
|
|
73
|
+
raise ArgumentError, "fsm_session_id must not be empty" if fsm_key.empty?
|
|
74
|
+
|
|
75
|
+
synchronize do
|
|
76
|
+
current = @workflow_admissions.fetch(key) do
|
|
77
|
+
raise Phronomy::Error, "Workflow instance #{key.inspect} has no Runtime admission"
|
|
78
|
+
end
|
|
79
|
+
unless current.owner_token.equal?(owner_token) && current.fsm_session_id.nil?
|
|
80
|
+
raise Phronomy::Error, "stale Workflow admission bind for #{key.inspect}"
|
|
81
|
+
end
|
|
82
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
83
|
+
workflow_instance_id: current.workflow_instance_id,
|
|
84
|
+
owner_token: current.owner_token,
|
|
85
|
+
fsm_session_id: fsm_key.freeze,
|
|
86
|
+
state: :executing
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @api private
|
|
93
|
+
def mark_workflow_admission(workflow_instance_id, owner_token:, state:)
|
|
94
|
+
assert_event_loop_thread!
|
|
95
|
+
key = workflow_instance_id.to_s
|
|
96
|
+
next_state = state.to_sym
|
|
97
|
+
unless %i[executing persisting_terminal recovery_required].include?(next_state)
|
|
98
|
+
raise ArgumentError, "unsupported Workflow admission state: #{next_state.inspect}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
synchronize do
|
|
102
|
+
current = @workflow_admissions.fetch(key) do
|
|
103
|
+
raise Phronomy::Error, "Workflow instance #{key.inspect} has no Runtime admission"
|
|
104
|
+
end
|
|
105
|
+
unless current.owner_token.equal?(owner_token)
|
|
106
|
+
raise Phronomy::Error, "stale Workflow admission update for #{key.inspect}"
|
|
107
|
+
end
|
|
108
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
109
|
+
workflow_instance_id: current.workflow_instance_id,
|
|
110
|
+
owner_token: current.owner_token,
|
|
111
|
+
fsm_session_id: current.fsm_session_id,
|
|
112
|
+
state: next_state
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Owner-aware release. A competing or stale attempt cannot release the
|
|
119
|
+
# current Workflow execution segment.
|
|
120
|
+
# @api private
|
|
121
|
+
def release_workflow(workflow_instance_id, owner_token:)
|
|
122
|
+
assert_event_loop_thread!
|
|
123
|
+
key = workflow_instance_id.to_s
|
|
124
|
+
synchronize do
|
|
125
|
+
current = @workflow_admissions[key]
|
|
126
|
+
next false unless current&.owner_token&.equal?(owner_token)
|
|
127
|
+
|
|
128
|
+
@workflow_admissions.delete(key)
|
|
129
|
+
true
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Read-only diagnostics used by internal tests and routing assertions.
|
|
134
|
+
def workflow_admission_owner(workflow_instance_id)
|
|
135
|
+
synchronize do
|
|
136
|
+
@workflow_admissions[workflow_instance_id.to_s]&.owner_token
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def workflow_admission_fsm_session_id(workflow_instance_id)
|
|
141
|
+
synchronize do
|
|
142
|
+
@workflow_admissions[workflow_instance_id.to_s]&.fsm_session_id
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def workflow_admission_state(workflow_instance_id)
|
|
147
|
+
synchronize do
|
|
148
|
+
@workflow_admissions[workflow_instance_id.to_s]&.state
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def post_to_workflow(workflow_instance_id:, event:, payload: nil)
|
|
153
|
+
@event_loop.__route_execution_event(self) do
|
|
154
|
+
admission = @workflow_admissions[workflow_instance_id.to_s]
|
|
155
|
+
next unless admission&.state == :executing && admission.fsm_session_id
|
|
156
|
+
|
|
157
|
+
Phronomy::Event.new(
|
|
158
|
+
type: event.to_sym, target_id: admission.fsm_session_id, payload: payload
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
def mark_workflow_recovery_required_for_session(fsm_session_id)
|
|
166
|
+
synchronize do
|
|
167
|
+
key, admission = @workflow_admissions.find do |_workflow_instance_id, candidate|
|
|
168
|
+
candidate.fsm_session_id == fsm_session_id.to_s
|
|
169
|
+
end
|
|
170
|
+
return false unless admission
|
|
171
|
+
|
|
172
|
+
@workflow_admissions[key] = WorkflowAdmission.new(
|
|
173
|
+
workflow_instance_id: admission.workflow_instance_id,
|
|
174
|
+
owner_token: admission.owner_token,
|
|
175
|
+
fsm_session_id: nil,
|
|
176
|
+
state: :recovery_required
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
true
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def workflow_admission_transition_in_progress_locked?
|
|
183
|
+
@workflow_admissions.values.any? do |admission|
|
|
184
|
+
%i[admitting executing persisting_terminal].include?(admission.state)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|