phronomy 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +9 -3
- data/benchmark/bench_agent_invoke.rb +25 -50
- data/benchmark/bench_context_assembler.rb +14 -11
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
- data/docs/architecture/agent-transition-ownership.md +13 -89
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +3 -3
- data/docs/architecture/context-management.md +1 -1
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +6 -0
- data/docs/architecture/multi-agent-handoff.md +6 -5
- data/docs/architecture/persistence.md +27 -9
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +10 -1
- data/docs/architecture/remaining-refactoring-plan.md +16 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +6 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
- data/docs/architecture.md +24 -11
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
- data/docs/decisions/032-storage-backend-composition.md +5 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
- data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
- data/docs/decisions/040-configuration-default-composition.md +12 -1
- data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
- data/docs/decisions/058-neutral-storage-primitives.md +5 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +18 -1
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/features.md +8 -3
- data/docs/getting-started.md +9 -6
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
- data/docs/migrations/handoff-runner-multi-agent.md +2 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +37 -32
- data/lib/phronomy/agent/base.rb +74 -72
- data/lib/phronomy/agent/before_llm_input.rb +64 -0
- data/lib/phronomy/agent/composition/run_once.rb +1 -1
- data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
- data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
- data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
- data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
- data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
- data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
- data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
- data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
- data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +182 -0
- data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
- data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
- data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
- data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
- data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +1 -21
- data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
- data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
- data/lib/phronomy/agent/persistence/watermark.rb +13 -11
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
- data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/storage_schema.rb +1 -0
- data/lib/phronomy/content_store/stored_contents.rb +2 -1
- data/lib/phronomy/context/assembly.rb +202 -0
- data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
- data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
- data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/engine/diagnostics.rb +1 -1
- data/lib/phronomy/engine/event_loop.rb +7 -7
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +1 -6
- data/lib/phronomy/engine/fsm_session.rb +3 -3
- data/lib/phronomy/engine/metrics.rb +16 -14
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +25 -12
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/{engine → execution}/execution.rb +61 -27
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
- data/lib/phronomy/generation/generator_verifier.rb +7 -7
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/multi_agent/shared_state.rb +2 -2
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
- data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +8 -2
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +549 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/tool/tool_executor.rb +58 -0
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +1 -1
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/workflow/execution/workflow.rb +7 -7
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
- data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +57 -16
- data/scripts/api_snapshot.rb +35 -15
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent.rbs +14 -138
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +17 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +0 -21
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent.rbs +6 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +1 -99
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
- data/sig/phronomy/tool.rbs +48 -4
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +1 -1
- data/sig/phronomy.rbs +0 -49
- metadata +318 -117
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -548
- data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
- data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
- data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
- data/lib/phronomy/agent/persistence/queries.rb +0 -61
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration/configuration.rb +0 -68
- data/lib/phronomy/configuration/global_configuration.rb +0 -26
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/engine/execution_receiver.rb +0 -65
- data/lib/phronomy/engine/runnable.rb +0 -54
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/llm_contract/token_usage.rb +0 -85
- data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
- data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
- data/lib/phronomy/persistence/api/persistence.rb +0 -140
- data/lib/phronomy/persistence_composition/repositories.rb +0 -77
- data/lib/phronomy/recovery/recovery.rb +0 -186
- data/lib/phronomy/tool/contract/tool_error.rb +0 -7
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
- data/sig/phronomy/execution_receiver.rbs +0 -34
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
- /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
- /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
class Persistence
|
|
5
|
+
# Execute short domain operations in one synchronous transaction. Participants
|
|
6
|
+
# bind their own storage adapters; this protocol does not select any domain.
|
|
7
|
+
# Explicit nesting remains a savepoint, never an independent commit.
|
|
8
|
+
# Storage failures whose commit outcome is fundamentally unknown remain
|
|
9
|
+
# backend/database failures; Phronomy does not claim exactly-once semantics
|
|
10
|
+
# for such failures. No automatic retry or rollback assumption is added.
|
|
11
|
+
# @api public
|
|
12
|
+
def atomic
|
|
13
|
+
scopes = Thread.current.thread_variable_get(:phronomy_persistence_scopes)
|
|
14
|
+
unless scopes
|
|
15
|
+
scopes = {}
|
|
16
|
+
Thread.current.thread_variable_set(:phronomy_persistence_scopes, scopes)
|
|
17
|
+
end
|
|
18
|
+
stack = (scopes[self] ||= [])
|
|
19
|
+
stack.last&.validate!
|
|
20
|
+
if backend.transaction_open? && stack.empty?
|
|
21
|
+
raise TransactionError, "cannot establish commit ownership inside an unrelated storage transaction"
|
|
22
|
+
end
|
|
23
|
+
scope = nil
|
|
24
|
+
result = StorageBoundary.call do
|
|
25
|
+
backend.transaction do |view|
|
|
26
|
+
scope = Transaction.new(self, view, parent: stack.last)
|
|
27
|
+
stack.push(scope)
|
|
28
|
+
begin
|
|
29
|
+
yield scope
|
|
30
|
+
ensure
|
|
31
|
+
scope.close!
|
|
32
|
+
stack.pop
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
scope.confirm!
|
|
37
|
+
result
|
|
38
|
+
ensure
|
|
39
|
+
scopes&.delete(self) if stack && stack.empty?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# A synchronous participation scope. Only storage adapters receive the raw
|
|
43
|
+
# view; domain operations exchange this scope and their own public values.
|
|
44
|
+
# @api public
|
|
45
|
+
class Transaction
|
|
46
|
+
def initialize(persistence, view, parent: nil)
|
|
47
|
+
@persistence, @view, @parent = persistence, view, parent
|
|
48
|
+
@open = true
|
|
49
|
+
@committed = false
|
|
50
|
+
@thread = Thread.current
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Bind a domain-owned storage adapter to this exact transaction. Exceptions
|
|
54
|
+
# poison this scope even if its caller rescues them inside the outer block.
|
|
55
|
+
# @api public
|
|
56
|
+
def participate(persistence:, adapter:)
|
|
57
|
+
validate!
|
|
58
|
+
unless @persistence.equal?(persistence)
|
|
59
|
+
raise TransactionError, "participation requires the same open Persistence scope"
|
|
60
|
+
end
|
|
61
|
+
StorageBoundary.call do
|
|
62
|
+
@view.atomic { |view| yield adapter.new(view) }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# A savepoint result is provisional until every enclosing scope commits.
|
|
67
|
+
# @api public
|
|
68
|
+
def outermost? = @parent.nil?
|
|
69
|
+
|
|
70
|
+
def committed? = @committed && (!@parent || @parent.committed?)
|
|
71
|
+
|
|
72
|
+
# @api private
|
|
73
|
+
def validate!
|
|
74
|
+
unless @open && @thread.equal?(Thread.current)
|
|
75
|
+
raise TransactionError, "participation requires its open synchronous context"
|
|
76
|
+
end
|
|
77
|
+
@view.validate!
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @api private
|
|
81
|
+
def close! = @open = false
|
|
82
|
+
# @api private
|
|
83
|
+
def confirm! = @committed = true
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -10,13 +10,18 @@ module Phronomy
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def self.resources
|
|
13
|
+
(agent_resources + [Phronomy::MultiAgent::Persistence::StorageSchema::HANDOFF_STATES,
|
|
14
|
+
Phronomy::MultiAgent::Persistence::StorageSchema::ROOTS,
|
|
15
|
+
Phronomy::MultiAgent::Persistence::StorageSchema::EXECUTIONS,
|
|
16
|
+
Phronomy::Workflow::Persistence::StorageSchema::STATES]).freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.agent_resources
|
|
13
20
|
[Agent::Persistence::StorageSchema::ROOTS,
|
|
14
21
|
Agent::Persistence::StorageSchema::EXECUTIONS,
|
|
15
22
|
Agent::Persistence::StorageSchema::JOURNAL,
|
|
16
|
-
Agent::Persistence::StorageSchema::
|
|
17
|
-
|
|
18
|
-
TeamStorageSchema::EXECUTIONS,
|
|
19
|
-
WorkflowStorageSchema::STATES,
|
|
23
|
+
Agent::Persistence::StorageSchema::RETENTIONS,
|
|
24
|
+
Agent::Persistence::StorageSchema::CANCELLATIONS,
|
|
20
25
|
ContentStore::StorageSchema::CONTENTS].freeze
|
|
21
26
|
end
|
|
22
27
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module PersistenceComposition
|
|
5
|
+
# The application's construction result, not an execution or query facade.
|
|
6
|
+
# Pass only the corresponding domain store to each domain's API.
|
|
7
|
+
Stores = Data.define(:coordinator, :agent, :multi_agent, :workflow)
|
|
8
|
+
|
|
9
|
+
# An ordinary Agent needs only its own records and content. Do not load or
|
|
10
|
+
# instantiate Team/Workflow implementations merely to construct an Agent.
|
|
11
|
+
def self.agent(backend: nil)
|
|
12
|
+
resources = StorageSchema.agent_resources
|
|
13
|
+
backend ||= Phronomy::Storage::Backends::InMemory.new(resources: resources)
|
|
14
|
+
coordinator = Phronomy::Persistence.new(backend: backend)
|
|
15
|
+
Phronomy::Persistence::StorageBoundary.call do
|
|
16
|
+
resources.each { |resource| backend.view.public_send(resource.kind, resource) }
|
|
17
|
+
end
|
|
18
|
+
Phronomy::Agent::Store.new(coordinator: coordinator, records: Phronomy::Agent::Persistence::Records)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.build(backend:)
|
|
22
|
+
coordinator = Phronomy::Persistence.new(backend: backend)
|
|
23
|
+
Phronomy::Persistence::StorageBoundary.call { StorageSchema.validate!(backend.view) }
|
|
24
|
+
agent = Phronomy::Agent::Store.new(coordinator: coordinator, records: Phronomy::Agent::Persistence::Records)
|
|
25
|
+
multi_agent = Phronomy::MultiAgent::Store.new(coordinator: coordinator, records: Phronomy::MultiAgent::Persistence::Records, agent_store: agent)
|
|
26
|
+
workflow = coordinator.bind(Phronomy::Workflow::Persistence::StateRepository)
|
|
27
|
+
Stores.new(coordinator: coordinator, agent: agent, multi_agent: multi_agent, workflow: workflow)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.in_memory
|
|
31
|
+
build(backend: Phronomy::Storage::Backends::InMemory.new(resources: StorageSchema.resources))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module PersistenceComposition
|
|
7
|
+
# Explicit offline conversion of a quiescent snapshot into an unpublished
|
|
8
|
+
# destination. Runtime codecs never call this converter.
|
|
9
|
+
# @api public
|
|
10
|
+
class Unit4Migration
|
|
11
|
+
def self.convert(snapshot, quiescent:)
|
|
12
|
+
raise ArgumentError, "stop every writer before migration" unless quiescent == true
|
|
13
|
+
new(snapshot).convert
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(snapshot)
|
|
17
|
+
@snapshot = Phronomy::CanonicalJSON.load(Phronomy::CanonicalJSON.dump(snapshot))
|
|
18
|
+
unless @snapshot.fetch("format") == "phronomy.snapshot/1" && @snapshot.fetch("revision") == "r8-unit3"
|
|
19
|
+
raise ArgumentError, "expected an r8-unit3 phronomy.snapshot/1 export"
|
|
20
|
+
end
|
|
21
|
+
@resources = @snapshot.fetch("resources")
|
|
22
|
+
@roots = index("agent.roots")
|
|
23
|
+
@executions = index("agent.executions")
|
|
24
|
+
@routing = index("handoff.states")
|
|
25
|
+
@blobs = index("content.blobs")
|
|
26
|
+
@holds, @cancellations = {}, {}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def convert
|
|
30
|
+
validate_source!
|
|
31
|
+
@executions.each_value { |entry| migrate_execution(entry) }
|
|
32
|
+
@routing.each_value { |entry| migrate_routing(entry) }
|
|
33
|
+
@resources["agent.retentions"] = {"kind" => "records", "entries" => @holds.values.sort_by { |entry| entry.fetch("key") }}
|
|
34
|
+
@resources["agent.cancellations"] = {"kind" => "records", "entries" => @cancellations.values.sort_by { |entry| entry.fetch("key") }}
|
|
35
|
+
@resources.fetch("content.blobs")["entries"] = @blobs.values.sort_by { |entry| entry.fetch("key") }
|
|
36
|
+
@snapshot["revision"] = "r8-unit4"
|
|
37
|
+
@snapshot["migration"] = {"source" => "r8-unit3", "logical_revisions" => "preserved", "physical_revisions" => "preserved"}
|
|
38
|
+
@snapshot["migration"]["resources_sha256"] = Digest::SHA256.hexdigest(Phronomy::CanonicalJSON.dump(@resources))
|
|
39
|
+
@snapshot
|
|
40
|
+
rescue KeyError, ArgumentError, Phronomy::Storage::SerializationError => error
|
|
41
|
+
raise Phronomy::Persistence::SerializationError, "Unit 4 migration aborted: #{error.message}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def index(id)
|
|
47
|
+
entries = @resources.fetch(id).fetch("entries")
|
|
48
|
+
result = entries.to_h { |entry| [entry.fetch("key"), entry] }
|
|
49
|
+
raise ArgumentError, "duplicate identity in #{id}" unless result.size == entries.size
|
|
50
|
+
result
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def validate_source!
|
|
54
|
+
expected = StorageSchema.resources.map(&:id) - %w[agent.retentions agent.cancellations]
|
|
55
|
+
raise ArgumentError, "source resource set differs from unit 3" unless @resources.keys.sort == expected.sort
|
|
56
|
+
@blobs.each do |key, entry|
|
|
57
|
+
bytes = [entry.fetch("hex")].pack("H*")
|
|
58
|
+
unless entry.fetch("hex").match?(/\A(?:[0-9a-f]{2})*\z/) && "sha256:#{Digest::SHA256.hexdigest(bytes)}" == key
|
|
59
|
+
raise ArgumentError, "content digest mismatch: #{key}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
@blobs.each_value do |entry|
|
|
63
|
+
bytes = [entry.fetch("hex")].pack("H*")
|
|
64
|
+
next unless bytes.lstrip.start_with?("{", "[")
|
|
65
|
+
begin
|
|
66
|
+
value = Phronomy::CanonicalJSON.load(bytes)
|
|
67
|
+
rescue Phronomy::Persistence::SerializationError, Phronomy::Storage::SerializationError, JSON::ParserError
|
|
68
|
+
next # Arbitrary text blobs are allowed.
|
|
69
|
+
end
|
|
70
|
+
validate_references!(value)
|
|
71
|
+
end
|
|
72
|
+
@roots.each do |id, entry|
|
|
73
|
+
root = Phronomy::Agent::Persistence::Codec.decode_agent_root(record(entry))
|
|
74
|
+
unless root.agent_id == id && root.agent_revision == entry.fetch("revision")
|
|
75
|
+
raise ArgumentError, "Agent root identity/revision mismatch: #{id}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
validate_references!(@resources)
|
|
79
|
+
validate_journal!
|
|
80
|
+
@executions.each do |id, entry|
|
|
81
|
+
envelope = entry.fetch("record")
|
|
82
|
+
unless envelope.fetch("record_type") == "phronomy.agent_execution" && envelope.fetch("format_version") == "0.1"
|
|
83
|
+
raise ArgumentError, "unsupported source execution format: #{id}"
|
|
84
|
+
end
|
|
85
|
+
body = envelope.fetch("payload")
|
|
86
|
+
Phronomy::Agent::Persistence::Codec.validate_agent_execution_payload!(body)
|
|
87
|
+
unless body.fetch("execution_id") == id && body.fetch("execution_revision") == entry.fetch("revision") && @roots.key?(body.fetch("agent_id"))
|
|
88
|
+
raise ArgumentError, "execution identity/revision/owner mismatch: #{id}"
|
|
89
|
+
end
|
|
90
|
+
attributes = {"owner" => body.fetch("agent_id"), "active" => %w[preparing active suspended].include?(body.fetch("status"))}
|
|
91
|
+
raise ArgumentError, "execution attributes mismatch: #{id}" unless entry.fetch("attributes") == attributes
|
|
92
|
+
[body["result_ref"], body["error_ref"], *body.fetch("working_records").map { |item| item["content_ref"] }].compact.each { |ref| fetch_bytes(ref) }
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def validate_references!(value)
|
|
97
|
+
case value
|
|
98
|
+
when Hash
|
|
99
|
+
value.each do |key, child|
|
|
100
|
+
if key.end_with?("_ref") && child.is_a?(String)
|
|
101
|
+
fetch_bytes(child)
|
|
102
|
+
elsif key.end_with?("_refs") && child.is_a?(Array)
|
|
103
|
+
child.each { |ref| fetch_bytes(ref) if ref.is_a?(String) }
|
|
104
|
+
end
|
|
105
|
+
validate_references!(child)
|
|
106
|
+
end
|
|
107
|
+
when Array then value.each { |child| validate_references!(child) }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def validate_journal!
|
|
112
|
+
source = @resources.fetch("agent.journal")
|
|
113
|
+
groups = source.fetch("entries").group_by { |entry| entry.fetch("stream") }
|
|
114
|
+
heads = source.fetch("heads")
|
|
115
|
+
raise ArgumentError, "journal has unknown owner" unless ((groups.keys + heads.keys).uniq - @roots.keys).empty?
|
|
116
|
+
@roots.each do |id, root|
|
|
117
|
+
position = root.fetch("record").fetch("payload").fetch("journal_position")
|
|
118
|
+
rows = groups.fetch(id, []).sort_by { |entry| entry.fetch("position") }
|
|
119
|
+
unless heads.fetch(id, 0) == position && rows.map { |entry| entry.fetch("position") } == (1..position).to_a
|
|
120
|
+
raise ArgumentError, "journal position mismatch: #{id}"
|
|
121
|
+
end
|
|
122
|
+
raise ArgumentError, "duplicate journal identity: #{id}" unless rows.map { |entry| entry.fetch("id") }.uniq.size == rows.size
|
|
123
|
+
rows.each do |entry|
|
|
124
|
+
value = Phronomy::Agent::Persistence::Codec.decode_journal_record(record(entry))
|
|
125
|
+
unless value.agent_id == id && value.sequence == entry.fetch("position") && value.record_id == entry.fetch("id")
|
|
126
|
+
raise ArgumentError, "journal entry identity mismatch: #{id}"
|
|
127
|
+
end
|
|
128
|
+
fetch_bytes(value.content_ref) if value.content_ref
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def migrate_execution(entry)
|
|
134
|
+
body = entry.fetch("record").fetch("payload")
|
|
135
|
+
id, owner = body.values_at("execution_id", "agent_id")
|
|
136
|
+
metadata = body.fetch("metadata")
|
|
137
|
+
if (correlation = metadata.delete("coordination"))
|
|
138
|
+
correlation.delete("handoff_revision") if correlation.fetch("kind") == "handoff"
|
|
139
|
+
metadata["reservation"] = correlation
|
|
140
|
+
if correlation.fetch("kind") == "handoff"
|
|
141
|
+
main = correlation.fetch("main_agent_id")
|
|
142
|
+
raise ArgumentError, "missing Handoff anchor for #{id}" unless @routing.key?(main)
|
|
143
|
+
metadata["execution_extension"] = binding("phronomy.handoff")
|
|
144
|
+
retain(owner, id, "handoff:#{main}")
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
cancelled = metadata.delete("coordination_cancel_requested") == true
|
|
148
|
+
if cancelled
|
|
149
|
+
metadata["cancellation_requested"] = true
|
|
150
|
+
@cancellations[id] = record_entry(id, 0, {"owner" => owner}, "phronomy.agent_cancellation", "0.1",
|
|
151
|
+
{"agent_id" => owner, "execution_id" => id})
|
|
152
|
+
end
|
|
153
|
+
if (ref = metadata.delete("multi_agent_coordination_ref"))
|
|
154
|
+
migrate_children(body, fetch_json(ref), cancelled)
|
|
155
|
+
end
|
|
156
|
+
if (target = metadata.delete("handoff_target_agent_id"))
|
|
157
|
+
target_execution = metadata.delete("handoff_target_execution_id") || raise(ArgumentError, "missing transfer execution: #{id}")
|
|
158
|
+
ref = metadata.delete("handoff_context_ref") || raise(ArgumentError, "missing transfer context: #{id}")
|
|
159
|
+
raise ArgumentError, "transfer receipt on unfinished Source: #{id}" unless body.fetch("status") == "handed_off"
|
|
160
|
+
Phronomy::Agent::TransferContext.from_h(fetch_json(ref))
|
|
161
|
+
main = metadata.fetch("reservation").fetch("main_agent_id")
|
|
162
|
+
metadata["transfer_receipt"] = {"target_agent_id" => target, "target_execution_id" => target_execution,
|
|
163
|
+
"context_ref" => ref, "owner_key" => "handoff:#{main}"}
|
|
164
|
+
retain(target, target_execution, "handoff:#{main}")
|
|
165
|
+
end
|
|
166
|
+
entry.fetch("record")["format_version"] = "0.2"
|
|
167
|
+
Phronomy::Agent::Persistence::Codec.validate_agent_execution_payload!(body)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def migrate_children(body, snapshot, cancelled)
|
|
171
|
+
id = body.fetch("execution_id")
|
|
172
|
+
metadata = body.fetch("metadata")
|
|
173
|
+
children = snapshot.fetch("children").map do |child|
|
|
174
|
+
child_agent, child_execution = child.values_at("agent_id", "execution_id")
|
|
175
|
+
existing = @executions[child_execution]&.fetch("record")&.fetch("payload")
|
|
176
|
+
raise ArgumentError, "subagent owner mismatch: #{child_execution}" if existing && existing.fetch("agent_id") != child_agent
|
|
177
|
+
retain(child_agent, child_execution, "subagent:#{id}") if @roots.key?(child_agent)
|
|
178
|
+
unless existing || child.fetch("state") == "reserved"
|
|
179
|
+
raise ArgumentError, "accepted child execution is missing: #{child_execution}"
|
|
180
|
+
end
|
|
181
|
+
if @roots.key?(child_agent)
|
|
182
|
+
root = @roots.fetch(child_agent).fetch("record").fetch("payload")
|
|
183
|
+
unless child.fetch("definition") == {"id" => root.fetch("agent_definition_id"), "version" => root.fetch("agent_definition_version")}
|
|
184
|
+
raise ArgumentError, "child definition mismatch: #{child_agent}"
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
raise ArgumentError, "unknown child error policy" unless %w[raise skip].include?(child.fetch("on_error"))
|
|
188
|
+
knowledge = fetch_json(child.fetch("knowledge_ref"))
|
|
189
|
+
knowledge.each { |item| Phronomy::Agent::KnowledgeItem.new(content: item.fetch("content"), metadata: item.fetch("metadata")) }
|
|
190
|
+
calls = Array(metadata[Phronomy::Agent::ExecutionMetadata::TOOL_BATCH_METADATA_KEY])
|
|
191
|
+
call = calls.find { |item| item.fetch("tool_invocation_id") == child.fetch("slot") }
|
|
192
|
+
imported = call ? %w[completed failed cancelled rejected].include?(call.fetch("status")) : body.fetch("phase") != "dispatching_tools"
|
|
193
|
+
{"slot" => child.fetch("slot"), "name" => child.fetch("name"), "definition" => child.fetch("definition"),
|
|
194
|
+
"agent_id" => child_agent, "execution_id" => child_execution,
|
|
195
|
+
"input" => fetch_bytes(child.fetch("input_ref")).force_encoding(Encoding::UTF_8),
|
|
196
|
+
"durable_context" => child["durable_context_ref"] && fetch_json(child.fetch("durable_context_ref")),
|
|
197
|
+
"knowledge" => knowledge, "on_error" => child.fetch("on_error"), "imported" => imported}
|
|
198
|
+
end
|
|
199
|
+
raise ArgumentError, "duplicate child slot: #{id}" unless children.map { |child| child.fetch("slot") }.uniq.size == children.size
|
|
200
|
+
ref = put_json("children" => children, "cancel_requested" => cancelled)
|
|
201
|
+
metadata["execution_extension"] = binding("phronomy.subagent", ref)
|
|
202
|
+
retain(body.fetch("agent_id"), id, "subagent:#{id}") unless children.empty?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def migrate_routing(entry)
|
|
206
|
+
envelope = entry.fetch("record")
|
|
207
|
+
unless envelope.fetch("record_type") == "phronomy.handoff_state" && envelope.fetch("format_version") == "0.1"
|
|
208
|
+
raise ArgumentError, "unsupported source Handoff routing format"
|
|
209
|
+
end
|
|
210
|
+
envelope["format_version"] = "0.2"
|
|
211
|
+
state = Phronomy::MultiAgent::Persistence::Codec.decode_handoff_state(record(entry))
|
|
212
|
+
unless entry.fetch("key") == state.main_agent_id && entry.fetch("revision") == state.handoff_revision
|
|
213
|
+
raise ArgumentError, "Handoff routing identity/revision mismatch"
|
|
214
|
+
end
|
|
215
|
+
main = state.main_agent_id
|
|
216
|
+
ids = [main, state.active_agent_id]
|
|
217
|
+
@executions.each_value do |execution|
|
|
218
|
+
body = execution.fetch("record").fetch("payload")
|
|
219
|
+
next unless body.dig("metadata", "reservation", "main_agent_id") == main
|
|
220
|
+
ids << body.fetch("agent_id")
|
|
221
|
+
receipt = body.dig("metadata", "transfer_receipt")
|
|
222
|
+
ids << receipt.fetch("target_agent_id") if receipt
|
|
223
|
+
end
|
|
224
|
+
ids = ids.uniq.sort
|
|
225
|
+
ids.each { |id| retain(id, nil, "handoff:#{main}") }
|
|
226
|
+
Phronomy::Agent::TransferContext.from_h(fetch_json(state.active_handoff_context_ref)) if state.active_handoff_context_ref
|
|
227
|
+
body = entry.fetch("record").fetch("payload")
|
|
228
|
+
body.fetch("metadata")["retained_agent_ids"] = ids
|
|
229
|
+
Array(state.metadata["cancelled_execution_ids"]).each do |execution_id|
|
|
230
|
+
cancelled = @executions[execution_id]&.fetch("record")&.fetch("payload")
|
|
231
|
+
next unless cancelled # A cancelled reservation can precede acceptance.
|
|
232
|
+
unless cancelled.dig("metadata", "reservation", "main_agent_id") == main
|
|
233
|
+
raise ArgumentError, "Handoff cancellation points outside its conversation: #{execution_id}"
|
|
234
|
+
end
|
|
235
|
+
@cancellations[execution_id] = record_entry(execution_id, 0, {"owner" => cancelled.fetch("agent_id")},
|
|
236
|
+
"phronomy.agent_cancellation", "0.1", {"agent_id" => cancelled.fetch("agent_id"), "execution_id" => execution_id})
|
|
237
|
+
end
|
|
238
|
+
if state.pending_source_execution_id
|
|
239
|
+
source = @executions.fetch(state.pending_source_execution_id).fetch("record").fetch("payload")
|
|
240
|
+
receipt = source.fetch("metadata").fetch("transfer_receipt")
|
|
241
|
+
unless receipt.fetch("target_execution_id") == state.pending_target_execution_id && receipt.fetch("target_agent_id") == state.active_agent_id && receipt.fetch("context_ref") == state.active_handoff_context_ref
|
|
242
|
+
raise ArgumentError, "Handoff pending identities/context do not match the Source receipt"
|
|
243
|
+
end
|
|
244
|
+
body.fetch("metadata")["source_agent_id"] = source.fetch("agent_id")
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def binding(key, ref = nil)
|
|
249
|
+
{"binding_key" => key, "binding_version" => 1, "state_ref" => ref}
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def retain(agent_id, execution_id, owner_key)
|
|
253
|
+
raise ArgumentError, "retained Agent is missing: #{agent_id}" unless @roots.key?(agent_id)
|
|
254
|
+
value = Phronomy::Agent::Retention.new(agent_id: agent_id, execution_id: execution_id, owner_key: owner_key)
|
|
255
|
+
key = Digest::SHA256.hexdigest(Phronomy::CanonicalJSON.dump(value.to_h))
|
|
256
|
+
@holds[key] = record_entry(key, 0, {"owner" => agent_id, "holder" => owner_key}, "phronomy.agent_retention", "0.1", value.to_h)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def record_entry(key, revision, attributes, type, version, payload)
|
|
260
|
+
{"key" => key, "revision" => revision, "attributes" => attributes,
|
|
261
|
+
"record" => {"record_type" => type, "format_version" => version, "payload" => payload}}
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def record(entry) = Phronomy::Storage::DurableRecord.new(**entry.fetch("record").transform_keys(&:to_sym))
|
|
265
|
+
def fetch_bytes(ref) = [@blobs.fetch(ref).fetch("hex")].pack("H*")
|
|
266
|
+
def fetch_json(ref) = Phronomy::CanonicalJSON.load(fetch_bytes(ref))
|
|
267
|
+
|
|
268
|
+
def put_json(value)
|
|
269
|
+
bytes = Phronomy::CanonicalJSON.dump(value)
|
|
270
|
+
key = "sha256:#{Digest::SHA256.hexdigest(bytes)}"
|
|
271
|
+
@blobs[key] ||= {"key" => key, "hex" => bytes.unpack1("H*"), "attributes" => {"canonicalization_version" => 1}}
|
|
272
|
+
key
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
# Select the Agent default at the application composition boundary. Binding
|
|
4
4
|
# does not create Persistence, global configuration, or a Runtime.
|
|
5
|
+
Phronomy::Agent::Base.context_policy(Phronomy::Context::DefaultPolicy.instance)
|
|
6
|
+
|
|
5
7
|
Phronomy::Agent::DefaultPersistence.install_factory(
|
|
6
|
-
-> { Phronomy::
|
|
8
|
+
-> { Phronomy::PersistenceComposition.agent }
|
|
7
9
|
)
|
|
10
|
+
|
|
11
|
+
Phronomy::Agent::ExecutionEnvironment.install_provider(-> { Phronomy::Agent::EngineEnvironment.new })
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require_relative "../configuration/runtime_settings"
|
|
5
|
+
require_relative "../agent/settings"
|
|
6
|
+
require_relative "../workflow/execution/workflow_settings"
|
|
7
|
+
require_relative "../tool/settings"
|
|
8
|
+
require_relative "../tracing/settings"
|
|
9
|
+
|
|
10
|
+
module Phronomy
|
|
11
|
+
# Application-facing configuration composes domain options and neutral runtime
|
|
12
|
+
# settings. Public accessors and constructor behavior stay unchanged.
|
|
13
|
+
class Configuration
|
|
14
|
+
extend Forwardable
|
|
15
|
+
|
|
16
|
+
DEFAULT_FACTORIES = {}
|
|
17
|
+
private_constant :DEFAULT_FACTORIES
|
|
18
|
+
|
|
19
|
+
# Bind fresh-instance factories once during application loading. Concrete
|
|
20
|
+
# component selection belongs to runtime_composition, not configuration.
|
|
21
|
+
# Applications replace instances through the existing configuration writers.
|
|
22
|
+
# @api private
|
|
23
|
+
def self.install_default_factories(tracer:, llm_adapter:)
|
|
24
|
+
DEFAULT_FACTORIES.replace(tracer: tracer, llm_adapter: llm_adapter).freeze
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_accessor :default_embedding_model, :multi_agent_store
|
|
29
|
+
|
|
30
|
+
# Preserve the public settings facade while each domain owns its values.
|
|
31
|
+
def_delegators :@__agent_settings, :default_model, :default_model=
|
|
32
|
+
def_delegators :@__agent_settings, :before_llm_input, :before_llm_input=
|
|
33
|
+
def_delegators :@__agent_settings, :agent_store, :agent_store=
|
|
34
|
+
def_delegators :@__agent_settings, :llm_adapter, :llm_adapter=
|
|
35
|
+
def_delegators :@__agent_settings, :stream_callback_error_policy, :stream_callback_error_policy=
|
|
36
|
+
def_delegators :@__agent_settings, :authorization_timeout, :authorization_timeout=
|
|
37
|
+
def_delegators :@__workflow_settings, :recursion_limit, :recursion_limit=
|
|
38
|
+
def_delegators :@__workflow_settings, :workflow_store, :workflow_store=
|
|
39
|
+
def_delegators :@__runtime_settings, :authorization_pool_size, :authorization_pool_size=
|
|
40
|
+
def_delegators :@__runtime_settings, :authorization_queue_size, :authorization_queue_size=
|
|
41
|
+
|
|
42
|
+
# @api private
|
|
43
|
+
attr_reader :__agent_settings, :__workflow_settings, :__tool_settings, :__tracing_settings
|
|
44
|
+
|
|
45
|
+
# Engine access is bound by the composition root, not by Engine itself.
|
|
46
|
+
# @api private
|
|
47
|
+
attr_reader :__runtime_settings
|
|
48
|
+
|
|
49
|
+
def tracer
|
|
50
|
+
@__tracing_settings.tracer
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def tracer=(value)
|
|
54
|
+
@__tracing_settings.tracer = value
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def trace_pii
|
|
58
|
+
@__tracing_settings.trace_pii
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def trace_pii=(value)
|
|
62
|
+
@__tracing_settings.trace_pii = value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def logger
|
|
66
|
+
@__runtime_settings.logger
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def logger=(value)
|
|
70
|
+
@__runtime_settings.logger = value
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def tool_result_max_size
|
|
74
|
+
@__tool_settings.max_result_size
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def tool_result_max_size=(value)
|
|
78
|
+
@__tool_settings.max_result_size = value
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def event_loop_stop_grace_seconds
|
|
82
|
+
@__runtime_settings.event_loop_stop_grace_seconds
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def event_loop_stop_grace_seconds=(value)
|
|
86
|
+
@__runtime_settings.event_loop_stop_grace_seconds = value
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def event_loop_starvation_threshold_seconds
|
|
90
|
+
@__runtime_settings.event_loop_starvation_threshold_seconds
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def event_loop_starvation_threshold_seconds=(value)
|
|
94
|
+
@__runtime_settings.event_loop_starvation_threshold_seconds = value
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def event_loop_dispatch_threshold_seconds
|
|
98
|
+
@__runtime_settings.event_loop_dispatch_threshold_seconds
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def event_loop_dispatch_threshold_seconds=(value)
|
|
102
|
+
@__runtime_settings.event_loop_dispatch_threshold_seconds = value
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def offload_pool_size
|
|
106
|
+
@__runtime_settings.offload_pool_size
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def offload_pool_size=(value)
|
|
110
|
+
@__runtime_settings.offload_pool_size = value
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def offload_queue_size
|
|
114
|
+
@__runtime_settings.offload_queue_size
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def offload_queue_size=(value)
|
|
118
|
+
@__runtime_settings.offload_queue_size = value
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def initialize
|
|
122
|
+
@__workflow_settings = WorkflowSettings.new(recursion_limit: 25)
|
|
123
|
+
@__runtime_settings = RuntimeSettings.new
|
|
124
|
+
@__tool_settings = Tool::Settings.new
|
|
125
|
+
@__tracing_settings = Tracing::Settings.new(tracer: DEFAULT_FACTORIES.fetch(:tracer).call)
|
|
126
|
+
@__agent_settings = Agent::Settings.new(
|
|
127
|
+
llm_adapter: DEFAULT_FACTORIES.fetch(:llm_adapter).call,
|
|
128
|
+
stream_callback_error_policy: :report, authorization_timeout: 5
|
|
129
|
+
)
|
|
130
|
+
@multi_agent_store = nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
# A scoped configuration copy owns its scalar settings while retaining the
|
|
136
|
+
# same injected tracer/logger identities, just like the previous flat object.
|
|
137
|
+
def initialize_copy(original)
|
|
138
|
+
super
|
|
139
|
+
@__runtime_settings = original.__runtime_settings.dup
|
|
140
|
+
@__agent_settings = original.__agent_settings.dup
|
|
141
|
+
@__workflow_settings = original.__workflow_settings.dup
|
|
142
|
+
@__tool_settings = original.__tool_settings.dup
|
|
143
|
+
@__tracing_settings = original.__tracing_settings.dup
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Binding creates no client, Configuration or Runtime. Resolve the configured
|
|
4
|
+
# adapter for every score at the existing read point; do not cache the client.
|
|
5
|
+
Phronomy::Testing::Eval::Scorer::LlmJudge.install_client_factory(
|
|
6
|
+
-> { Phronomy::LLMAdapter::AsyncClient.new(adapter: Phronomy.configuration.llm_adapter) }
|
|
7
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Global configuration access, replacement, and scoped overrides.
|
|
4
|
+
# Explicitly loaded by the application entry point; not a common definition.
|
|
5
|
+
module Phronomy
|
|
6
|
+
class << self
|
|
7
|
+
def configuration
|
|
8
|
+
@configuration ||= Configuration.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def configure
|
|
12
|
+
yield configuration
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def reset_configuration!
|
|
16
|
+
@configuration = Configuration.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def with_configuration
|
|
20
|
+
original = @configuration&.dup
|
|
21
|
+
yield configuration
|
|
22
|
+
ensure
|
|
23
|
+
@configuration = original
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The provider yields only the Engine-facing value object, never Configuration.
|
|
29
|
+
# It is intentionally lazy and follows reset_configuration!/with_configuration.
|
|
30
|
+
Phronomy::RuntimeSettings.install_provider { Phronomy.configuration.__runtime_settings }
|
|
31
|
+
|
|
32
|
+
# Domain accessors are lazy too. Each returns only the owning domain's values
|
|
33
|
+
# or operation, never the application Configuration or a captured snapshot.
|
|
34
|
+
Phronomy::Agent::Settings.install_provider { Phronomy.configuration.__agent_settings }
|
|
35
|
+
Phronomy::WorkflowSettings.install_provider { Phronomy.configuration.__workflow_settings }
|
|
36
|
+
Phronomy::Tool::Settings.install_provider { Phronomy.configuration.__tool_settings }
|
|
37
|
+
Phronomy::Tracing::Settings.install_provider { Phronomy.configuration.__tracing_settings }
|
|
38
|
+
Phronomy::MultiAgent::Store.install_configured_provider { Phronomy.configuration.multi_agent_store }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Select stores and execution connections at the application composition
|
|
4
|
+
# boundary, without constructing either during library loading.
|
|
5
|
+
Phronomy::MultiAgent::TeamCoordinator.install_persistence_factory(
|
|
6
|
+
-> { Phronomy::PersistenceComposition.in_memory.multi_agent }
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
Phronomy::MultiAgent::ExecutionEnvironment.install_provider(-> { Phronomy::MultiAgent::EngineEnvironment.new })
|