phronomy 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +9 -3
- data/benchmark/bench_agent_invoke.rb +25 -50
- data/benchmark/bench_context_assembler.rb +14 -11
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
- data/docs/architecture/agent-transition-ownership.md +13 -89
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +3 -3
- data/docs/architecture/context-management.md +1 -1
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +6 -0
- data/docs/architecture/multi-agent-handoff.md +6 -5
- data/docs/architecture/persistence.md +27 -9
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +10 -1
- data/docs/architecture/remaining-refactoring-plan.md +16 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +6 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
- data/docs/architecture.md +24 -11
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
- data/docs/decisions/032-storage-backend-composition.md +5 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
- data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
- data/docs/decisions/040-configuration-default-composition.md +12 -1
- data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
- data/docs/decisions/058-neutral-storage-primitives.md +5 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +18 -1
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/features.md +8 -3
- data/docs/getting-started.md +9 -6
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
- data/docs/migrations/handoff-runner-multi-agent.md +2 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +37 -32
- data/lib/phronomy/agent/base.rb +74 -72
- data/lib/phronomy/agent/before_llm_input.rb +64 -0
- data/lib/phronomy/agent/composition/run_once.rb +1 -1
- data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
- data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
- data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
- data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
- data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
- data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
- data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
- data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
- data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +182 -0
- data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
- data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
- data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
- data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
- data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +1 -21
- data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
- data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
- data/lib/phronomy/agent/persistence/watermark.rb +13 -11
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
- data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/storage_schema.rb +1 -0
- data/lib/phronomy/content_store/stored_contents.rb +2 -1
- data/lib/phronomy/context/assembly.rb +202 -0
- data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
- data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
- data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/engine/diagnostics.rb +1 -1
- data/lib/phronomy/engine/event_loop.rb +7 -7
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +1 -6
- data/lib/phronomy/engine/fsm_session.rb +3 -3
- data/lib/phronomy/engine/metrics.rb +16 -14
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +25 -12
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/{engine → execution}/execution.rb +61 -27
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
- data/lib/phronomy/generation/generator_verifier.rb +7 -7
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/multi_agent/shared_state.rb +2 -2
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
- data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +8 -2
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +549 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/tool/tool_executor.rb +58 -0
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +1 -1
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/workflow/execution/workflow.rb +7 -7
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
- data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +57 -16
- data/scripts/api_snapshot.rb +35 -15
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent.rbs +14 -138
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +17 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +0 -21
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent.rbs +6 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +1 -99
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
- data/sig/phronomy/tool.rbs +48 -4
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +1 -1
- data/sig/phronomy.rbs +0 -49
- metadata +318 -117
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -548
- data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
- data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
- data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
- data/lib/phronomy/agent/persistence/queries.rb +0 -61
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration/configuration.rb +0 -68
- data/lib/phronomy/configuration/global_configuration.rb +0 -26
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/engine/execution_receiver.rb +0 -65
- data/lib/phronomy/engine/runnable.rb +0 -54
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/llm_contract/token_usage.rb +0 -85
- data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
- data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
- data/lib/phronomy/persistence/api/persistence.rb +0 -140
- data/lib/phronomy/persistence_composition/repositories.rb +0 -77
- data/lib/phronomy/recovery/recovery.rb +0 -186
- data/lib/phronomy/tool/contract/tool_error.rb +0 -7
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
- data/sig/phronomy/execution_receiver.rbs +0 -34
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
- /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
- /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
|
@@ -27,6 +27,7 @@ module Phronomy
|
|
|
27
27
|
"arguments" => serializable_value(child.raw_arguments || {}),
|
|
28
28
|
"status" => child.status.to_s
|
|
29
29
|
}
|
|
30
|
+
entry["validated_arguments"] = serializable_value(child.arguments) if child.arguments
|
|
30
31
|
if child.execution_completed?
|
|
31
32
|
entry["result"] = serializable_value(child.result)
|
|
32
33
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
4
|
|
|
5
5
|
module Phronomy
|
|
6
6
|
module Agent
|
|
@@ -10,10 +10,6 @@ module Phronomy
|
|
|
10
10
|
class ExecutionOutcomeCommitter
|
|
11
11
|
include Phronomy::Concurrency::WorkerInputRestricted
|
|
12
12
|
|
|
13
|
-
HandoffTerminalView = Data.define(
|
|
14
|
-
:target_agent_id, :responsibility, :selection_intent,
|
|
15
|
-
:llm_call_id, :tool_call_id, :policy
|
|
16
|
-
)
|
|
17
13
|
TerminalView = Data.define(
|
|
18
14
|
:phase, :output, :usage, :approval_request, :rejected,
|
|
19
15
|
:input_blocked, :output_blocked, :block_error,
|
|
@@ -22,7 +18,7 @@ module Phronomy
|
|
|
22
18
|
Command = Data.define(
|
|
23
19
|
:execution_id, :fsm_session_id, :expected_execution_revision,
|
|
24
20
|
:root, :journal_records, :execution, :runtime_snapshot,
|
|
25
|
-
:terminal_view, :state_required
|
|
21
|
+
:terminal_view, :state_required, :wiring
|
|
26
22
|
)
|
|
27
23
|
Outcome = Data.define(
|
|
28
24
|
:type, :execution, :root, :appended_records,
|
|
@@ -40,121 +36,88 @@ module Phronomy
|
|
|
40
36
|
view = operation.terminal_view
|
|
41
37
|
error = view.callback_failure&.to_stream_callback_error || view.source_error ||
|
|
42
38
|
view.block_error || view.invocation_error
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
change = ExecutionChange.new(agent: @agent, current: operation.execution,
|
|
40
|
+
root: operation.root, kind: :terminal, terminal: view, config: operation.wiring) do |tx, state, receipt, pending|
|
|
41
|
+
if pending
|
|
42
|
+
waiting = operation.execution.with(metadata: extension_metadata(operation.execution, state).merge(
|
|
43
|
+
"cancellation_requested" => change.cancel_requested || operation.execution.metadata["cancellation_requested"] == true
|
|
44
|
+
))
|
|
45
|
+
save_execution(tx, operation.execution, waiting)
|
|
46
|
+
Outcome.new(type: :coordination_wait, execution: waiting, root: operation.root,
|
|
47
|
+
appended_records: [].freeze, result: nil,
|
|
48
|
+
error: error || Phronomy::ExecutionRehydrationRequiredError.new("Execution retains unfinished participant work"), approval_request: nil)
|
|
49
|
+
else
|
|
50
|
+
raise error if error.is_a?(Phronomy::ExecutionRehydrationRequiredError)
|
|
51
|
+
commit_terminal(tx, operation, state, receipt, error)
|
|
52
|
+
end
|
|
47
53
|
end
|
|
48
|
-
|
|
49
|
-
return commit_failed_outcome(operation, error) if error
|
|
50
|
-
return commit_suspended(operation) if view.phase == :suspended
|
|
51
|
-
commit_completed(operation)
|
|
52
|
-
rescue => caught
|
|
53
|
-
reconcile_terminal_error(operation, caught)
|
|
54
|
+
change.perform
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
private
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
next unless unresolved
|
|
71
|
-
waiting = current.with(metadata: refreshed.metadata.merge(
|
|
72
|
-
"coordination_cancel_requested" => operation.terminal_view.cancel_requested || current.metadata["coordination_cancel_requested"] == true
|
|
73
|
-
))
|
|
74
|
-
tx.executions.save(current.execution_id, expected_revision: current.execution_revision, execution: waiting)
|
|
59
|
+
def commit_terminal(tx, operation, state, receipt, error)
|
|
60
|
+
view = operation.terminal_view
|
|
61
|
+
if !error && view.phase == :suspended
|
|
62
|
+
suspended = encode_suspension(tx, operation)
|
|
63
|
+
suspended = with_extension(suspended, state)
|
|
64
|
+
save_execution(tx, operation.execution, suspended)
|
|
65
|
+
root = save_suspended_root(tx, operation.root)
|
|
66
|
+
return Outcome.new(type: :suspended, execution: suspended, root: root,
|
|
67
|
+
appended_records: [].freeze,
|
|
68
|
+
result: result_base(suspended, root).merge(suspended: true, approval_request: view.approval_request).freeze,
|
|
69
|
+
error: nil, approval_request: view.approval_request)
|
|
75
70
|
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
coordination_wait_outcome(operation, confirmed, error)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def coordination_wait_outcome(operation, execution, error)
|
|
85
|
-
Outcome.new(type: :coordination_wait, execution: execution, root: operation.root,
|
|
86
|
-
appended_records: [].freeze, result: nil,
|
|
87
|
-
error: error.is_a?(Phronomy::ExecutionRehydrationRequiredError) ? error :
|
|
88
|
-
Phronomy::ExecutionRehydrationRequiredError.new("Execution #{execution.execution_id} retains unfinished children for cancellation/recovery"),
|
|
89
|
-
approval_request: nil)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# F1: terminal atomicity alone does not establish commit outcome certainty.
|
|
93
|
-
# Reuse an exact committed outcome; an absent/active/read-failed result is
|
|
94
|
-
# never permission to write a second terminal transition.
|
|
95
|
-
def reconcile_terminal_error(operation, error)
|
|
96
|
-
confirmed = @persistence.executions.load(operation.execution_id)
|
|
97
|
-
raise error unless confirmed.terminal? &&
|
|
98
|
-
confirmed.agent_id == @agent.agent_id &&
|
|
99
|
-
confirmed.execution_revision == operation.expected_execution_revision + 1
|
|
100
|
-
root = @persistence.agents.load(@agent.agent_id)
|
|
101
|
-
records = @persistence.journals.read(@agent.agent_id,
|
|
102
|
-
after: operation.root.journal_position, limit: root.journal_position - operation.root.journal_position)
|
|
103
|
-
result = @persistence.execution_result(confirmed.execution_id)
|
|
104
|
-
failure = result[:error] && RecoverySupport.error_from_failure(result[:error])
|
|
105
|
-
type = if failure
|
|
106
|
-
:failed
|
|
71
|
+
records, execution = if error
|
|
72
|
+
encode_failure(tx, operation, error)
|
|
73
|
+
elsif view.handoff
|
|
74
|
+
raise Phronomy::ConfigurationError, "Control transfer needs a transaction participant" unless receipt
|
|
75
|
+
encode_transfer(tx, operation, receipt)
|
|
107
76
|
else
|
|
108
|
-
(
|
|
77
|
+
encode_completion(tx, operation)
|
|
109
78
|
end
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
79
|
+
execution = with_extension(execution, state)
|
|
80
|
+
appended = append_journal(tx, operation.root, records)
|
|
81
|
+
save_execution(tx, operation.execution, execution)
|
|
82
|
+
root = save_terminal_root(tx, operation.root, appended)
|
|
83
|
+
if error
|
|
84
|
+
Outcome.new(type: :failed, execution: execution, root: root, appended_records: appended.freeze,
|
|
85
|
+
result: nil, error: error, approval_request: nil)
|
|
86
|
+
elsif view.handoff
|
|
87
|
+
Outcome.new(type: :handed_off, execution: execution, root: root, appended_records: appended.freeze,
|
|
88
|
+
result: result_base(execution, root).freeze, error: nil, approval_request: nil)
|
|
89
|
+
else
|
|
90
|
+
messages = transcript_messages(root, operation.journal_records + appended, persistence: tx)
|
|
91
|
+
completed_outcome(view, execution, root, appended, messages)
|
|
122
92
|
end
|
|
123
|
-
request = operation.terminal_view.approval_request
|
|
124
|
-
Outcome.new(type: :suspended, execution: suspended, root: next_root,
|
|
125
|
-
appended_records: [].freeze,
|
|
126
|
-
result: result_base(suspended, next_root).merge(suspended: true, approval_request: request).freeze,
|
|
127
|
-
error: nil, approval_request: request)
|
|
128
93
|
end
|
|
129
94
|
|
|
130
|
-
def
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
records, completed = encode_completion(tx, operation)
|
|
134
|
-
appended = append_journal(tx, operation.root, records)
|
|
135
|
-
completed = save_coordinated_execution(tx, operation.execution, completed)
|
|
136
|
-
next_root = save_terminal_root(tx, operation.root, appended)
|
|
95
|
+
def extension_metadata(execution, state)
|
|
96
|
+
execution.metadata.merge("execution_extension" => state&.to_h).compact
|
|
97
|
+
end
|
|
137
98
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
messages = transcript_messages(next_root,
|
|
141
|
-
operation.journal_records + Array(appended), persistence: tx)
|
|
142
|
-
end
|
|
143
|
-
completed_outcome(operation.terminal_view, completed, next_root, appended, messages)
|
|
99
|
+
def with_extension(execution, state)
|
|
100
|
+
execution.with(execution_revision: execution.execution_revision, metadata: extension_metadata(execution, state))
|
|
144
101
|
end
|
|
145
102
|
|
|
146
|
-
def
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
appended = append_journal(tx, operation.root, records)
|
|
152
|
-
failed = save_coordinated_execution(tx, operation.execution, failed)
|
|
153
|
-
next_root = save_terminal_root(tx, operation.root, appended)
|
|
103
|
+
def encode_transfer(tx, operation, receipt)
|
|
104
|
+
request = operation.terminal_view.handoff
|
|
105
|
+
unless receipt.fetch("target_agent_id") == request.target_agent_id &&
|
|
106
|
+
!receipt.fetch("target_execution_id").to_s.empty? && !receipt.fetch("context_ref").to_s.empty?
|
|
107
|
+
raise Phronomy::Persistence::StateConflictError, "Control transfer receipt mismatch"
|
|
154
108
|
end
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
109
|
+
current = operation.execution
|
|
110
|
+
encoded, calls = encode_runtime_records(tx, operation, context_candidate: false)
|
|
111
|
+
audit_ref = tx.contents.put_json("target_agent_id" => request.target_agent_id,
|
|
112
|
+
"responsibility" => request.responsibility, "selection" => request.selection.transform_keys(&:to_s))
|
|
113
|
+
audit = JournalRecord.new(agent_id: @agent.agent_id, execution_id: current.execution_id,
|
|
114
|
+
llm_call_id: request.llm_call_id, kind: :execution_handed_off, channel: :audit,
|
|
115
|
+
content_ref: audit_ref, context_generation: operation.root.transcript_generation, context_candidate: false,
|
|
116
|
+
metadata: {"target_agent_id" => request.target_agent_id, "handoff_tool_call_id" => request.tool_call_id}.compact)
|
|
117
|
+
updated = current.with(status: :handed_off, phase: :handed_off, working_records: [],
|
|
118
|
+
llm_calls: current.llm_calls + calls, approval_request: nil, terminal_reason: "handed_off",
|
|
119
|
+
metadata: current.metadata.merge("transfer_receipt" => receipt))
|
|
120
|
+
[current.working_records + encoded + [audit], updated]
|
|
158
121
|
end
|
|
159
122
|
|
|
160
123
|
def encode_suspension(tx, operation)
|
|
@@ -264,25 +227,6 @@ module Phronomy
|
|
|
264
227
|
expected_position: root.journal_position, records: records)
|
|
265
228
|
end
|
|
266
229
|
|
|
267
|
-
def save_coordinated_execution(tx, current, updated)
|
|
268
|
-
coordinated = @agent.__prepare_coordination_record(updated, tx: tx)
|
|
269
|
-
synchronize_handoff_target(tx, coordinated)
|
|
270
|
-
save_execution(tx, current, coordinated)
|
|
271
|
-
coordinated
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
def synchronize_handoff_target(tx, execution)
|
|
275
|
-
coordination = execution.metadata["coordination"]
|
|
276
|
-
return unless coordination && coordination["kind"] == "handoff"
|
|
277
|
-
routing = tx.handoff_states.load(coordination.fetch("main_agent_id"))
|
|
278
|
-
return unless routing && routing.pending_target_execution_id == execution.execution_id && routing.phase != "stable"
|
|
279
|
-
unless routing.active_agent_id == execution.agent_id
|
|
280
|
-
raise Phronomy::Storage::ConflictError, "Handoff Target owner mismatch"
|
|
281
|
-
end
|
|
282
|
-
tx.handoff_states.save(routing.main_agent_id, expected_revision: routing.handoff_revision,
|
|
283
|
-
state: routing.with(phase: "stable"))
|
|
284
|
-
end
|
|
285
|
-
|
|
286
230
|
def save_execution(tx, current, updated)
|
|
287
231
|
tx.executions.save(current.execution_id,
|
|
288
232
|
expected_revision: current.execution_revision, execution: updated)
|
|
@@ -318,7 +262,7 @@ module Phronomy
|
|
|
318
262
|
end
|
|
319
263
|
|
|
320
264
|
def transcript_messages(root, journal_records, persistence: @persistence)
|
|
321
|
-
materializer =
|
|
265
|
+
materializer = RuntimeInput.new(
|
|
322
266
|
agent: @agent,
|
|
323
267
|
persistence: persistence
|
|
324
268
|
)
|
|
@@ -6,6 +6,10 @@ module Phronomy
|
|
|
6
6
|
# The EventLoop remains the sole writer during execution.
|
|
7
7
|
# @api private
|
|
8
8
|
class ExecutionRegistry < Phronomy::ExecutionReceiver
|
|
9
|
+
def self.existing_current
|
|
10
|
+
ExecutionEnvironment.current.existing_registry
|
|
11
|
+
end
|
|
12
|
+
|
|
9
13
|
# Immutable Agent-owned value. The map containing these records is the
|
|
10
14
|
# mutable authority; records are replaced rather than mutated in place.
|
|
11
15
|
AgentExecutionState = Data.define(
|
|
@@ -36,7 +40,7 @@ module Phronomy
|
|
|
36
40
|
PhysicalCompletion = Data.define(:execution_id, :token)
|
|
37
41
|
private_constant :UNSET, :PhysicalCompletion
|
|
38
42
|
|
|
39
|
-
def initialize(
|
|
43
|
+
def initialize(channel:)
|
|
40
44
|
super
|
|
41
45
|
@agent_admissions = {}
|
|
42
46
|
@agent_executions = {}
|
|
@@ -364,7 +368,7 @@ module Phronomy
|
|
|
364
368
|
callback = lambda do
|
|
365
369
|
accepted = post_message(PhysicalCompletion.new(execution_id: key, token: token))
|
|
366
370
|
unless accepted
|
|
367
|
-
Phronomy.
|
|
371
|
+
Phronomy::RuntimeSettings.current.logger&.warn(
|
|
368
372
|
"[Phronomy] EventLoop rejected physical-completion delivery for #{key}"
|
|
369
373
|
)
|
|
370
374
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
4
|
|
|
5
5
|
module Phronomy
|
|
6
6
|
module Agent
|
|
@@ -11,10 +11,9 @@ module Phronomy
|
|
|
11
11
|
class ExecutionSessionRunner
|
|
12
12
|
include Phronomy::Concurrency::WorkerInputRestricted
|
|
13
13
|
|
|
14
|
-
def initialize(
|
|
14
|
+
def initialize(environment:, on_complete:)
|
|
15
15
|
@on_complete = on_complete
|
|
16
|
-
@
|
|
17
|
-
@event_loop = runtime.event_loop
|
|
16
|
+
@environment = environment
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def register(session, result_task, source_name: "#{result_task.name}-source")
|
|
@@ -29,20 +28,19 @@ module Phronomy
|
|
|
29
28
|
fsm_session_id: session.id
|
|
30
29
|
)
|
|
31
30
|
end
|
|
32
|
-
@
|
|
31
|
+
@environment.register_session(session, completion: source)
|
|
33
32
|
session
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def resume(invocation, result_task, resume_event:, resume_phase:,
|
|
37
36
|
source_name: "#{result_task.name}-source")
|
|
38
37
|
assert_event_loop!
|
|
39
|
-
session =
|
|
40
|
-
|
|
38
|
+
session = @environment.build_agent_session(
|
|
39
|
+
invocation: invocation,
|
|
41
40
|
resume_event: resume_event,
|
|
42
|
-
resume_phase: resume_phase
|
|
43
|
-
runtime: @runtime
|
|
41
|
+
resume_phase: resume_phase
|
|
44
42
|
)
|
|
45
|
-
|
|
43
|
+
@environment.registry.replace_agent_execution(
|
|
46
44
|
invocation.execution_id,
|
|
47
45
|
invocation: invocation,
|
|
48
46
|
fsm_session_id: session.id
|
|
@@ -58,20 +56,18 @@ module Phronomy
|
|
|
58
56
|
resume_event: :resume, resume_phase: :suspended)
|
|
59
57
|
invocation.tool_invocations.each do |child|
|
|
60
58
|
session = if child.awaiting_approval?
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
@environment.build_tool_session(
|
|
60
|
+
invocation: child,
|
|
61
|
+
parent_sink: parent.event_sink,
|
|
64
62
|
resume_event: approved ? :approve : :reject,
|
|
65
|
-
resume_phase: :awaiting_approval
|
|
66
|
-
runtime: @runtime
|
|
63
|
+
resume_phase: :awaiting_approval
|
|
67
64
|
)
|
|
68
65
|
elsif !approved && child.authorized?
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
@environment.build_tool_session(
|
|
67
|
+
invocation: child,
|
|
68
|
+
parent_sink: parent.event_sink,
|
|
72
69
|
resume_event: :cancel,
|
|
73
|
-
resume_phase: :authorized
|
|
74
|
-
runtime: @runtime
|
|
70
|
+
resume_phase: :authorized
|
|
75
71
|
)
|
|
76
72
|
end
|
|
77
73
|
register_child(child, session, parent.event_sink) if session
|
|
@@ -84,12 +80,11 @@ module Phronomy
|
|
|
84
80
|
resume_event: :resume, resume_phase: :suspended,
|
|
85
81
|
source_name: "framework-tool-recovery-source")
|
|
86
82
|
invocation.tool_invocations.select(&:authorized?).each do |child|
|
|
87
|
-
session =
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
session = @environment.build_tool_session(
|
|
84
|
+
invocation: child,
|
|
85
|
+
parent_sink: parent.event_sink,
|
|
90
86
|
resume_event: :dispatch,
|
|
91
|
-
resume_phase: :authorized
|
|
92
|
-
runtime: @runtime
|
|
87
|
+
resume_phase: :authorized
|
|
93
88
|
)
|
|
94
89
|
register_child(child, session, parent.event_sink)
|
|
95
90
|
end
|
|
@@ -105,11 +100,11 @@ module Phronomy
|
|
|
105
100
|
child.mark_framework_failed!(error)
|
|
106
101
|
parent_event_sink.post(:tool_failed, {tool_invocation_id: child.id})
|
|
107
102
|
end
|
|
108
|
-
@
|
|
103
|
+
@environment.register_session(session, completion: completion)
|
|
109
104
|
end
|
|
110
105
|
|
|
111
106
|
def assert_event_loop!
|
|
112
|
-
return if @
|
|
107
|
+
return if @environment.executing?
|
|
113
108
|
|
|
114
109
|
raise Phronomy::Error, "Agent session registration must run on EventLoop"
|
|
115
110
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../../
|
|
3
|
+
require_relative "../../execution/concurrency/worker_input_restricted"
|
|
4
4
|
|
|
5
5
|
require "securerandom"
|
|
6
6
|
require "time"
|
|
@@ -49,9 +49,9 @@ module Phronomy
|
|
|
49
49
|
# A durable nonterminal execution keeps Runtime admission fail-closed
|
|
50
50
|
# until recovery can establish its lineage, including after F4 loss.
|
|
51
51
|
return unadmitted_result(operation, error, :recovery_required)
|
|
52
|
-
rescue Phronomy::
|
|
53
|
-
Phronomy::
|
|
54
|
-
Phronomy::
|
|
52
|
+
rescue Phronomy::Persistence::ConflictError,
|
|
53
|
+
Phronomy::Persistence::NotFoundError,
|
|
54
|
+
Phronomy::Persistence::SerializationError,
|
|
55
55
|
ArgumentError,
|
|
56
56
|
Phronomy::ConfigurationError => error
|
|
57
57
|
return unadmitted_result(operation, error, :not_established)
|
|
@@ -97,7 +97,7 @@ module Phronomy
|
|
|
97
97
|
filtered_input: nil,
|
|
98
98
|
config: operation.config,
|
|
99
99
|
appended_records: [].freeze,
|
|
100
|
-
error:
|
|
100
|
+
error: error,
|
|
101
101
|
admission_outcome: outcome
|
|
102
102
|
)
|
|
103
103
|
end
|
|
@@ -114,7 +114,7 @@ module Phronomy
|
|
|
114
114
|
# Advance the failure base only after the commit response is known.
|
|
115
115
|
# F1 response loss must not be reported as a confirmed terminal result.
|
|
116
116
|
current_execution = active_execution
|
|
117
|
-
projection =
|
|
117
|
+
projection = RuntimeInput.new(
|
|
118
118
|
agent: @agent, persistence: @persistence
|
|
119
119
|
).materialize(manifest: manifest, manifest_ref: manifest_ref)
|
|
120
120
|
Result.new(
|
|
@@ -166,7 +166,7 @@ module Phronomy
|
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
def prepare_context(staged, root, input, config, journal_records)
|
|
169
|
-
assembler =
|
|
169
|
+
assembler = ContextPreparation.new(
|
|
170
170
|
agent: @agent, persistence: @persistence, journal_records: journal_records
|
|
171
171
|
)
|
|
172
172
|
prepared = assembler.prepare_initial(
|
|
@@ -184,7 +184,7 @@ module Phronomy
|
|
|
184
184
|
active = manifest = manifest_ref = nil
|
|
185
185
|
@persistence.transaction do |tx|
|
|
186
186
|
assert_local_durable_base!(tx, root)
|
|
187
|
-
manifest, manifest_ref =
|
|
187
|
+
manifest, manifest_ref = Phronomy::Context::Assembly.new.store(prepared, contents: tx.contents)
|
|
188
188
|
active = execution_with_initial_manifest(staged, manifest_ref)
|
|
189
189
|
tx.executions.save(
|
|
190
190
|
staged.execution_id,
|
|
@@ -208,26 +208,15 @@ module Phronomy
|
|
|
208
208
|
end
|
|
209
209
|
|
|
210
210
|
def admit_execution(raw_message, root:, mode: :invoke, config: {}, preparation_replayable: false)
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
admission = Admission.new(persistence: @persistence, root: root,
|
|
212
|
+
input: raw_message, config: config,
|
|
213
|
+
preparation_metadata: initial_preparation_metadata(mode.to_sym, preparation_replayable))
|
|
214
|
+
participant = config[:phronomy_admission]
|
|
215
|
+
if admission.correlation && !participant
|
|
216
|
+
raise Phronomy::ConfigurationError, "Coordinated admission requires its current owner"
|
|
213
217
|
end
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
preparation_metadata = initial_preparation_metadata(mode.to_sym, preparation_replayable)
|
|
217
|
-
@persistence.transaction do |tx|
|
|
218
|
-
execution = build_admitted_execution(
|
|
219
|
-
tx, raw_message, root: root, config: config,
|
|
220
|
-
preparation_metadata: preparation_metadata
|
|
221
|
-
)
|
|
222
|
-
validate_coordination_admission!(tx, execution)
|
|
223
|
-
tx.executions.create_active(execution)
|
|
224
|
-
next_root = root.with(
|
|
225
|
-
agent_revision: root.agent_revision + 1,
|
|
226
|
-
lifecycle_status: :active
|
|
227
|
-
)
|
|
228
|
-
tx.agents.save(root.agent_id, expected_revision: root.agent_revision, root: next_root)
|
|
229
|
-
end
|
|
230
|
-
[execution, next_root]
|
|
218
|
+
participant ? participant.admit(admission) : admission.accept
|
|
219
|
+
admission.result
|
|
231
220
|
end
|
|
232
221
|
|
|
233
222
|
def initial_preparation_metadata(mode, replayable)
|
|
@@ -240,92 +229,9 @@ module Phronomy
|
|
|
240
229
|
}
|
|
241
230
|
end
|
|
242
231
|
|
|
243
|
-
def build_admitted_execution(tx, raw_message, root:, config:, preparation_metadata:)
|
|
244
|
-
input_ref = tx.contents.put_text(raw_message)
|
|
245
|
-
durable_context_ref = if config.key?(:durable_context)
|
|
246
|
-
tx.contents.put_json(config.fetch(:durable_context))
|
|
247
|
-
end
|
|
248
|
-
input_record = JournalRecord.new(
|
|
249
|
-
agent_id: @agent.agent_id,
|
|
250
|
-
kind: :input_received,
|
|
251
|
-
channel: :external,
|
|
252
|
-
role: :user,
|
|
253
|
-
content_ref: input_ref,
|
|
254
|
-
context_generation: root.transcript_generation,
|
|
255
|
-
context_candidate: false
|
|
256
|
-
)
|
|
257
|
-
execution = AgentExecution.start(
|
|
258
|
-
agent_root: root,
|
|
259
|
-
input_record: input_record,
|
|
260
|
-
execution_id: config[:phronomy_reserved_execution_id] || SecureRandom.uuid,
|
|
261
|
-
metadata: {
|
|
262
|
-
"coordination" => config[:phronomy_coordination],
|
|
263
|
-
"current_input_ref" => input_ref,
|
|
264
|
-
"durable_context_ref" => durable_context_ref
|
|
265
|
-
}.merge(preparation_metadata).compact
|
|
266
|
-
)
|
|
267
|
-
input_record = JournalRecord.from_h(input_record.to_h.merge("execution_id" => execution.execution_id))
|
|
268
|
-
execution.with(execution_revision: 0, working_records: [input_record])
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def validate_coordination_admission!(tx, execution)
|
|
272
|
-
owner = execution.metadata["coordination"]
|
|
273
|
-
return unless owner
|
|
274
|
-
|
|
275
|
-
case owner.fetch("kind")
|
|
276
|
-
when "team" then validate_team_admission!(tx, execution, owner)
|
|
277
|
-
when "subagent" then validate_subagent_admission!(tx, execution, owner)
|
|
278
|
-
when "handoff" then validate_handoff_admission!(tx, execution, owner)
|
|
279
|
-
else
|
|
280
|
-
raise Phronomy::ConfigurationError, "Unknown coordination owner kind"
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def validate_team_admission!(tx, execution, owner)
|
|
285
|
-
team = tx.team_executions.load(owner.fetch("team_execution_id"))
|
|
286
|
-
unless team.team_id == owner.fetch("team_id") && team.active? && !team.metadata["cancel_requested"]
|
|
287
|
-
raise Phronomy::CancellationError, "Team run is no longer dispatchable"
|
|
288
|
-
end
|
|
289
|
-
slot = if owner.fetch("slot") == "coordinator"
|
|
290
|
-
team.coordinator
|
|
291
|
-
else
|
|
292
|
-
assignment = team.assignments.find { |entry| entry.fetch("task_id") == owner.fetch("slot") }
|
|
293
|
-
worker = assignment && team.workers.fetch(assignment.fetch("worker"))
|
|
294
|
-
worker&.merge("execution_id" => assignment.fetch("execution_id"))
|
|
295
|
-
end
|
|
296
|
-
unless slot && slot.fetch("execution_id") == execution.execution_id && slot.fetch("agent_id") == execution.agent_id
|
|
297
|
-
raise Phronomy::Storage::ConflictError, "Team reserved child identity mismatch"
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def validate_subagent_admission!(tx, execution, owner)
|
|
302
|
-
parent = tx.executions.load(owner.fetch("parent_execution_id"))
|
|
303
|
-
unless parent.agent_id == owner.fetch("parent_agent_id") && parent.active? && !parent.metadata["coordination_cancel_requested"]
|
|
304
|
-
raise Phronomy::CancellationError, "Parent run is no longer dispatchable"
|
|
305
|
-
end
|
|
306
|
-
snapshot = tx.contents.fetch_json(parent.metadata.fetch("multi_agent_coordination_ref"))
|
|
307
|
-
slot = snapshot.fetch("children").find { |entry| entry.fetch("slot") == owner.fetch("slot") }
|
|
308
|
-
unless slot && slot.fetch("agent_id") == execution.agent_id && slot.fetch("execution_id") == execution.execution_id
|
|
309
|
-
raise Phronomy::Storage::ConflictError, "Parent reserved child identity mismatch"
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
def validate_handoff_admission!(tx, execution, owner)
|
|
314
|
-
routing = tx.handoff_states.load(owner.fetch("main_agent_id"))
|
|
315
|
-
unless routing && routing.active_agent_id == execution.agent_id
|
|
316
|
-
raise Phronomy::Storage::ConflictError, "Handoff responsibility changed before admission"
|
|
317
|
-
end
|
|
318
|
-
if Array(routing.metadata["cancelled_execution_ids"]).include?(execution.execution_id)
|
|
319
|
-
raise Phronomy::CancellationError, "Handoff reservation was cancelled"
|
|
320
|
-
end
|
|
321
|
-
if routing.phase != "stable" && routing.pending_target_execution_id != execution.execution_id
|
|
322
|
-
raise Phronomy::Storage::ConflictError, "Handoff reserved Target identity mismatch"
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
232
|
def recovered_config(execution)
|
|
327
233
|
mode = (execution.metadata[ExecutionMetadata::INVOCATION_MODE_KEY] || "invoke").to_sym
|
|
328
|
-
config = {phronomy_recovery_mode: mode}.merge(@agent.
|
|
234
|
+
config = {phronomy_recovery_mode: mode}.merge(@agent.__execution_wiring)
|
|
329
235
|
if execution.metadata.key?("durable_context_ref")
|
|
330
236
|
context = @persistence.contents.fetch_json(execution.metadata.fetch("durable_context_ref"))
|
|
331
237
|
unless context.is_a?(Hash)
|
|
@@ -353,7 +259,7 @@ module Phronomy
|
|
|
353
259
|
end
|
|
354
260
|
|
|
355
261
|
def commit_preparation_failure(execution, root, error)
|
|
356
|
-
translated_error =
|
|
262
|
+
translated_error = error
|
|
357
263
|
failed = next_root = appended = nil
|
|
358
264
|
@persistence.transaction do |tx|
|
|
359
265
|
error_ref = tx.contents.put_json(
|
|
@@ -412,10 +318,6 @@ module Phronomy
|
|
|
412
318
|
journal_position: root.journal_position
|
|
413
319
|
)
|
|
414
320
|
end
|
|
415
|
-
|
|
416
|
-
def translated(error)
|
|
417
|
-
@agent.send(:_translated_error, error)
|
|
418
|
-
end
|
|
419
321
|
end
|
|
420
322
|
end
|
|
421
323
|
end
|