phronomy 0.27.0 → 0.29.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 +28 -7
- 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/application-recipes.md +229 -0
- 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/dx05-agent-scope.md +119 -0
- data/docs/architecture/dx05-workflow-task-state.md +134 -0
- data/docs/architecture/error-api-review.md +245 -0
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +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/failure-reason-codes.md +45 -0
- data/docs/features.md +12 -4
- data/docs/getting-started.md +52 -48
- 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/ordered-event-delivery.md +54 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/docs/workflow-completion.md +92 -0
- data/gemfiles/http_minimum.gemfile +5 -0
- 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/agent_not_found_error.rb +16 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
- data/lib/phronomy/agent/api/agent.rb +13 -0
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +132 -103
- data/lib/phronomy/agent/base.rb +146 -113
- data/lib/phronomy/agent/before_llm_input.rb +70 -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 +55 -32
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
- 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 +19 -120
- 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 +8 -11
- 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 +188 -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/lifetime_api.rb +76 -0
- data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
- data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
- data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
- data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
- data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
- 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 +13 -12
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
- 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} +3 -3
- 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/common/error.rb +65 -1
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/base.rb +7 -2
- 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 +195 -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/authentication_error.rb +11 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/rate_limit_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/{engine → execution}/execution_cancellation_error.rb +2 -2
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
- 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 +9 -4
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
- 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/generation/low_confidence_error.rb +2 -2
- data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
- 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 +60 -44
- 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_busy_error.rb +18 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
- data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
- 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/storage/condition_failed_error.rb +2 -2
- data/lib/phronomy/storage/unique_constraint_error.rb +2 -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 +551 -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 +36 -7
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
- 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 +37 -9
- 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 +28 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
- data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
- data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
- data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -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 +61 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +63 -16
- data/scripts/api_snapshot.rb +47 -15
- data/scripts/check_readme_ruby.rb +24 -29
- data/scripts/check_readme_runnable.rb +92 -81
- 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/agent_not_found_error.rbs +6 -0
- data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -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/stream_callback_error.rbs +8 -0
- data/sig/phronomy/agent.rbs +29 -135
- 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 +23 -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 +1 -21
- data/sig/phronomy/filter/filter_block_error.rbs +6 -0
- data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/integrations.rbs +14 -0
- 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/team_busy_error.rbs +8 -0
- data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -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} +4 -18
- 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 +15 -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 +5 -1
- data/sig/phronomy.rbs +4 -49
- metadata +365 -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}/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
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../../../engine/concurrency/worker_input_restricted"
|
|
4
|
-
|
|
5
|
-
module Phronomy
|
|
6
|
-
module Agent
|
|
7
|
-
module Context
|
|
8
|
-
module Capability
|
|
9
|
-
# Base class extending RubyLLM::Tool with Phronomy-specific DSL.
|
|
10
|
-
class Base < RubyLLM::Tool
|
|
11
|
-
include Phronomy::Concurrency::WorkerInputRestricted
|
|
12
|
-
|
|
13
|
-
class << self
|
|
14
|
-
# @api public
|
|
15
|
-
def tool_name(value = nil)
|
|
16
|
-
return @tool_name || super() if value.nil?
|
|
17
|
-
|
|
18
|
-
@tool_name = value.to_s
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# RubyLLM stores Tool descriptions in a class-instance variable.
|
|
22
|
-
# Preserve normal class inheritance semantics so Phronomy's anonymous
|
|
23
|
-
# decorator subclasses do not lose their parent's description.
|
|
24
|
-
# @api public
|
|
25
|
-
def description(text = nil)
|
|
26
|
-
unless text
|
|
27
|
-
return @description if instance_variable_defined?(:@description)
|
|
28
|
-
return superclass.description if superclass.respond_to?(:description)
|
|
29
|
-
|
|
30
|
-
return nil
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
@description = text
|
|
34
|
-
end
|
|
35
|
-
alias_method :desc, :description
|
|
36
|
-
|
|
37
|
-
# Phronomy declarations inherit through anonymous Tool decorators.
|
|
38
|
-
# RubyLLM owns schema construction and provider request rendering.
|
|
39
|
-
# @api public
|
|
40
|
-
def declared_parameters
|
|
41
|
-
return @declared_parameters if instance_variable_defined?(:@declared_parameters)
|
|
42
|
-
|
|
43
|
-
@declared_parameters = superclass.declared_parameters.dup
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Keep Phronomy's parameter reader and support RubyLLM's schema DSL.
|
|
47
|
-
# @api public
|
|
48
|
-
def parameters(schema = :__phronomy_read__, &block)
|
|
49
|
-
return declared_parameters if schema == :__phronomy_read__ && !block
|
|
50
|
-
|
|
51
|
-
super((schema == :__phronomy_read__) ? nil : schema, &block)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# @api public
|
|
55
|
-
def parameters_schema_definition
|
|
56
|
-
return @parameters_schema_definition if instance_variable_defined?(:@parameters_schema_definition)
|
|
57
|
-
|
|
58
|
-
superclass.parameters_schema_definition
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# @api public
|
|
62
|
-
def params_schema_definition
|
|
63
|
-
parameters_schema_definition
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# @api public
|
|
67
|
-
def params(schema = nil, &block)
|
|
68
|
-
parameters(schema, &block)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# @api public
|
|
72
|
-
def provider_options(options = :__phronomy_read__)
|
|
73
|
-
return super unless options == :__phronomy_read__
|
|
74
|
-
return @provider_options if instance_variable_defined?(:@provider_options)
|
|
75
|
-
|
|
76
|
-
@provider_options = duplicate_configuration(superclass.provider_options)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# @api public
|
|
80
|
-
def provider_params
|
|
81
|
-
provider_options
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# @api public
|
|
85
|
-
def with_params(**options)
|
|
86
|
-
provider_options(options)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# @api public
|
|
90
|
-
def param(name, enum: nil, properties: nil, desc: nil, **options)
|
|
91
|
-
options[:description] = desc if desc
|
|
92
|
-
parameter(name, **options)
|
|
93
|
-
param_enums[name] = duplicate_configuration(enum) if enum
|
|
94
|
-
param_schemas[name] = normalize_nested_schema(properties) if properties
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# @api public
|
|
98
|
-
def param_enums
|
|
99
|
-
return @param_enums if instance_variable_defined?(:@param_enums)
|
|
100
|
-
|
|
101
|
-
parent = superclass.respond_to?(:param_enums) ? superclass.param_enums : {}
|
|
102
|
-
@param_enums = duplicate_configuration(parent)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# @api public
|
|
106
|
-
def param_schemas
|
|
107
|
-
return @param_schemas if instance_variable_defined?(:@param_schemas)
|
|
108
|
-
|
|
109
|
-
parent = superclass.respond_to?(:param_schemas) ? superclass.param_schemas : {}
|
|
110
|
-
@param_schemas = duplicate_configuration(parent)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
private
|
|
114
|
-
|
|
115
|
-
def duplicate_configuration(value)
|
|
116
|
-
case value
|
|
117
|
-
when Hash
|
|
118
|
-
value.to_h do |key, child|
|
|
119
|
-
[key, duplicate_configuration(child)]
|
|
120
|
-
end
|
|
121
|
-
when Array
|
|
122
|
-
value.map { |child| duplicate_configuration(child) }
|
|
123
|
-
else
|
|
124
|
-
value
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def normalize_nested_schema(props)
|
|
129
|
-
props.transform_keys(&:to_sym).transform_values do |spec|
|
|
130
|
-
normalized = spec.transform_keys(&:to_sym)
|
|
131
|
-
normalized[:type] ||= :string
|
|
132
|
-
if normalized[:properties]
|
|
133
|
-
normalized[:properties] = normalize_nested_schema(normalized[:properties])
|
|
134
|
-
end
|
|
135
|
-
normalized
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
public
|
|
140
|
-
|
|
141
|
-
# Declares whether Tool work is safe to run cooperatively on the EventLoop
|
|
142
|
-
# or must be offloaded to a bounded worker pool.
|
|
143
|
-
#
|
|
144
|
-
# Phronomy does not classify the reason for offloading. Blocking I/O,
|
|
145
|
-
# CPU-bound synchronous work, and other long synchronous calls all use
|
|
146
|
-
# +:offloaded+. The application owns that workload classification.
|
|
147
|
-
# @api public
|
|
148
|
-
def execution_mode(value = nil)
|
|
149
|
-
if value.nil?
|
|
150
|
-
return @execution_mode if instance_variable_defined?(:@execution_mode)
|
|
151
|
-
return superclass.execution_mode if superclass.respond_to?(:execution_mode)
|
|
152
|
-
|
|
153
|
-
return :offloaded
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
valid = %i[cooperative offloaded]
|
|
157
|
-
unless valid.include?(value)
|
|
158
|
-
raise ArgumentError,
|
|
159
|
-
"execution_mode must be one of #{valid.inspect}, got #{value.inspect}"
|
|
160
|
-
end
|
|
161
|
-
@execution_mode = value
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Configures execution-error handling. Supported values are :raise
|
|
165
|
-
# and :suppress only.
|
|
166
|
-
# @api public
|
|
167
|
-
def on_error(behavior = nil)
|
|
168
|
-
if behavior.nil?
|
|
169
|
-
return @on_error if instance_variable_defined?(:@on_error)
|
|
170
|
-
return superclass.on_error if superclass.respond_to?(:on_error)
|
|
171
|
-
|
|
172
|
-
return :raise
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
valid = %i[raise suppress]
|
|
176
|
-
unless valid.include?(behavior)
|
|
177
|
-
raise ArgumentError,
|
|
178
|
-
"on_error must be one of #{valid.inspect}, got #{behavior.inspect}"
|
|
179
|
-
end
|
|
180
|
-
@on_error = behavior
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
# @api public
|
|
184
|
-
def on_schema_error(behavior = nil)
|
|
185
|
-
if behavior.nil?
|
|
186
|
-
return @on_schema_error if instance_variable_defined?(:@on_schema_error)
|
|
187
|
-
return superclass.on_schema_error if superclass.respond_to?(:on_schema_error)
|
|
188
|
-
|
|
189
|
-
return :return_error
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
@on_schema_error = behavior
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
# @api public
|
|
196
|
-
def requires_approval(value = :__unset__, &block)
|
|
197
|
-
if block
|
|
198
|
-
unless value == :__unset__
|
|
199
|
-
raise ArgumentError, "pass either a value or a block to requires_approval"
|
|
200
|
-
end
|
|
201
|
-
@requires_approval = block
|
|
202
|
-
elsif value == :__unset__
|
|
203
|
-
return @requires_approval unless @requires_approval.nil?
|
|
204
|
-
return superclass.requires_approval if superclass < RubyLLM::Tool
|
|
205
|
-
|
|
206
|
-
false
|
|
207
|
-
else
|
|
208
|
-
unless value == true || value == false || value.respond_to?(:call)
|
|
209
|
-
raise ArgumentError, "requires_approval must be true, false, or callable"
|
|
210
|
-
end
|
|
211
|
-
@requires_approval = value
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
# @api public
|
|
216
|
-
def approval_facts(&block)
|
|
217
|
-
if block
|
|
218
|
-
@approval_facts = block
|
|
219
|
-
elsif instance_variable_defined?(:@approval_facts)
|
|
220
|
-
@approval_facts
|
|
221
|
-
elsif superclass.respond_to?(:approval_facts)
|
|
222
|
-
superclass.approval_facts
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
# @api public
|
|
227
|
-
def redact_params(*names)
|
|
228
|
-
if names.empty?
|
|
229
|
-
parent = superclass.respond_to?(:redact_params) ? superclass.redact_params : []
|
|
230
|
-
((@redacted_params || []) + parent).uniq
|
|
231
|
-
else
|
|
232
|
-
@redacted_params = ((@redacted_params || []) + names.map(&:to_sym)).uniq
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# @api public
|
|
237
|
-
def max_result_size(value = :__unset__)
|
|
238
|
-
if value == :__unset__
|
|
239
|
-
return @max_result_size if instance_variable_defined?(:@max_result_size)
|
|
240
|
-
return superclass.max_result_size if superclass.respond_to?(:max_result_size)
|
|
241
|
-
|
|
242
|
-
return nil
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
@max_result_size = value
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def name
|
|
250
|
-
self.class.tool_name || super
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def parameters_schema
|
|
254
|
-
schema = super
|
|
255
|
-
return schema if schema.nil?
|
|
256
|
-
|
|
257
|
-
properties = schema.dig("properties") || schema.dig(:properties)
|
|
258
|
-
return schema unless properties
|
|
259
|
-
|
|
260
|
-
self.class.param_enums.each do |param_name, values|
|
|
261
|
-
key = properties.key?(param_name.to_s) ? param_name.to_s : param_name.to_sym
|
|
262
|
-
next unless properties[key]
|
|
263
|
-
|
|
264
|
-
param_type = properties[key]["type"]
|
|
265
|
-
properties[key]["enum"] = values.map do |value|
|
|
266
|
-
case param_type
|
|
267
|
-
when "integer"
|
|
268
|
-
value.is_a?(Integer) ? value : Integer(value.to_s)
|
|
269
|
-
when "number"
|
|
270
|
-
value.is_a?(Numeric) ? value : Float(value.to_s)
|
|
271
|
-
when "boolean"
|
|
272
|
-
unless value == true || value == false
|
|
273
|
-
raise ArgumentError,
|
|
274
|
-
"boolean enum values must be true or false (got: #{value.inspect})"
|
|
275
|
-
end
|
|
276
|
-
value
|
|
277
|
-
else
|
|
278
|
-
value.to_s
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
self.class.param_schemas.each do |param_name, nested|
|
|
284
|
-
key = properties.key?(param_name.to_s) ? param_name.to_s : param_name.to_sym
|
|
285
|
-
next unless properties[key]
|
|
286
|
-
properties[key]["properties"] = nested_schema_to_json_schema(nested)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
schema
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
# Phronomy retains these readers as part of its Tool contract.
|
|
293
|
-
# @api public
|
|
294
|
-
def params_schema
|
|
295
|
-
parameters_schema
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
# @api public
|
|
299
|
-
def provider_params
|
|
300
|
-
provider_options
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
# @api public
|
|
304
|
-
def parameters
|
|
305
|
-
self.class.declared_parameters
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
# @api public
|
|
309
|
-
def call(args, cancellation_token: nil)
|
|
310
|
-
cancellation_token&.raise_if_cancelled!
|
|
311
|
-
validated_args, schema_error = validate_and_coerce(args)
|
|
312
|
-
if schema_error
|
|
313
|
-
case self.class.on_schema_error
|
|
314
|
-
when :raise
|
|
315
|
-
raise Phronomy::ToolError,
|
|
316
|
-
"#{self.class.name} schema error: #{schema_error}"
|
|
317
|
-
else
|
|
318
|
-
return "Schema validation failed: #{schema_error}"
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
if cancellation_token && execute_accepts_cancellation_token?
|
|
323
|
-
validated_args = validated_args.merge(cancellation_token: cancellation_token)
|
|
324
|
-
end
|
|
325
|
-
result = super(**(validated_args || {}).transform_keys(&:to_sym))
|
|
326
|
-
truncate_result_if_needed(result)
|
|
327
|
-
rescue Phronomy::ToolError, Phronomy::CancellationError
|
|
328
|
-
raise
|
|
329
|
-
rescue => error
|
|
330
|
-
if self.class.on_error == :suppress
|
|
331
|
-
msg = "[Phronomy] Tool #{self.class.name} suppressed error: " \
|
|
332
|
-
"#{error.class}: #{error.message}"
|
|
333
|
-
if Phronomy.configuration.logger
|
|
334
|
-
Phronomy.configuration.logger.warn(msg)
|
|
335
|
-
else
|
|
336
|
-
warn msg
|
|
337
|
-
end
|
|
338
|
-
"Tool error suppressed: #{error.message}"
|
|
339
|
-
else
|
|
340
|
-
raise Phronomy::ToolError,
|
|
341
|
-
"#{self.class.name} execution failed: #{error.message}"
|
|
342
|
-
end
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
# @api public
|
|
346
|
-
def call_async(
|
|
347
|
-
args,
|
|
348
|
-
cancellation_token: nil,
|
|
349
|
-
config: {}
|
|
350
|
-
)
|
|
351
|
-
Phronomy::Agent::Context::Capability::ToolExecutor.call_async(
|
|
352
|
-
tool: self,
|
|
353
|
-
args: args,
|
|
354
|
-
cancellation_token: cancellation_token,
|
|
355
|
-
config: config
|
|
356
|
-
)
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
def requires_approval
|
|
360
|
-
self.class.requires_approval
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
def requires_approval?
|
|
364
|
-
self.class.requires_approval
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
# @api public
|
|
368
|
-
def tool_origin
|
|
369
|
-
:local
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
# @api public
|
|
373
|
-
def approval_metadata
|
|
374
|
-
{}
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
# @api public
|
|
378
|
-
def execute(**_args)
|
|
379
|
-
raise NotImplementedError, "#{self.class}#execute is not implemented"
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
private
|
|
383
|
-
|
|
384
|
-
def execute_accepts_cancellation_token?
|
|
385
|
-
method(:execute).parameters.any? do |type, name|
|
|
386
|
-
name == :cancellation_token && %i[key keyreq].include?(type)
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def truncate_result_if_needed(result)
|
|
391
|
-
max = self.class.max_result_size || Phronomy.configuration.tool_result_max_size
|
|
392
|
-
return result unless max && result.respond_to?(:length) && result.length > max
|
|
393
|
-
|
|
394
|
-
msg = "[Phronomy] Tool #{self.class.name} result truncated " \
|
|
395
|
-
"(#{result.length} chars > #{max} limit)"
|
|
396
|
-
if Phronomy.configuration.logger
|
|
397
|
-
Phronomy.configuration.logger.warn(msg)
|
|
398
|
-
else
|
|
399
|
-
warn msg
|
|
400
|
-
end
|
|
401
|
-
"#{result[0, max]}...[truncated]"
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
def redacted_args(args)
|
|
405
|
-
redacted = self.class.redact_params
|
|
406
|
-
return args if redacted.empty?
|
|
407
|
-
|
|
408
|
-
args.each_with_object({}) do |(key, value), result|
|
|
409
|
-
result[key] = redacted.include?(key.to_sym) ? "[REDACTED]" : value
|
|
410
|
-
end
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
def validate_and_coerce(args)
|
|
414
|
-
return [args, nil] if self.class.parameters.empty?
|
|
415
|
-
|
|
416
|
-
normalized = (args || {}).transform_keys(&:to_sym)
|
|
417
|
-
coerce_mode = self.class.on_schema_error == :coerce
|
|
418
|
-
result = {}
|
|
419
|
-
|
|
420
|
-
self.class.parameters.each do |name, param|
|
|
421
|
-
value = normalized[name]
|
|
422
|
-
if value.nil?
|
|
423
|
-
return [nil, "required parameter '#{name}' is missing"] if param.required
|
|
424
|
-
next
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
if coerce_mode
|
|
428
|
-
coerced, error = coerce_value(value, param.type)
|
|
429
|
-
return [nil, error] if error
|
|
430
|
-
value = coerced
|
|
431
|
-
else
|
|
432
|
-
error = type_error(value, param.type)
|
|
433
|
-
return [nil, error] if error
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
if param.type.to_sym == :object
|
|
437
|
-
nested_schema = self.class.param_schemas[name]
|
|
438
|
-
if nested_schema
|
|
439
|
-
error = validate_nested_object(value, nested_schema, name.to_s)
|
|
440
|
-
return [nil, error] if error
|
|
441
|
-
end
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
enum_vals = self.class.param_enums[name]
|
|
445
|
-
if enum_vals && !enum_vals.map(&:to_s).include?(value.to_s)
|
|
446
|
-
return [nil,
|
|
447
|
-
"parameter '#{name}' must be one of: #{enum_vals.join(", ")} " \
|
|
448
|
-
"(got: #{value.inspect})"]
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
result[name] = value
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
extra = normalized.keys - self.class.parameters.keys
|
|
455
|
-
unless extra.empty?
|
|
456
|
-
return [nil, "unknown parameter(s): #{extra.inspect}"]
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
[result, nil]
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
def nested_schema_to_json_schema(nested)
|
|
463
|
-
nested.each_with_object({}) do |(prop_name, spec), result|
|
|
464
|
-
entry = {"type" => spec[:type].to_s}
|
|
465
|
-
entry["description"] = spec[:desc] if spec[:desc]
|
|
466
|
-
entry["enum"] = spec[:enum] if spec[:enum]
|
|
467
|
-
if spec[:properties]
|
|
468
|
-
entry["properties"] = nested_schema_to_json_schema(spec[:properties])
|
|
469
|
-
end
|
|
470
|
-
result[prop_name.to_s] = entry
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
def validate_nested_object(value, properties, path)
|
|
475
|
-
return "field '#{path}' must be an object (Hash)" unless value.is_a?(Hash)
|
|
476
|
-
|
|
477
|
-
normalized = value.transform_keys(&:to_sym)
|
|
478
|
-
extra = normalized.keys - properties.keys
|
|
479
|
-
unless extra.empty?
|
|
480
|
-
return "nested field '#{path}' contains undeclared key(s): #{extra.inspect}"
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
properties.each do |name, spec|
|
|
484
|
-
field_path = "#{path}.#{name}"
|
|
485
|
-
field_value = normalized[name]
|
|
486
|
-
|
|
487
|
-
if field_value.nil?
|
|
488
|
-
return "nested required field '#{field_path}' is missing" if spec[:required]
|
|
489
|
-
next
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
error = type_error(field_value, spec[:type])
|
|
493
|
-
return "nested field '#{field_path}': #{error}" if error
|
|
494
|
-
|
|
495
|
-
next unless spec[:type].to_sym == :object && spec[:properties]
|
|
496
|
-
|
|
497
|
-
error = validate_nested_object(field_value, spec[:properties], field_path)
|
|
498
|
-
return error if error
|
|
499
|
-
end
|
|
500
|
-
nil
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
def type_error(value, declared_type)
|
|
504
|
-
return nil if value.nil?
|
|
505
|
-
|
|
506
|
-
ok = case declared_type.to_sym
|
|
507
|
-
when :string then value.is_a?(String)
|
|
508
|
-
when :integer then value.is_a?(Integer)
|
|
509
|
-
when :number, :float then value.is_a?(Numeric)
|
|
510
|
-
when :boolean then [true, false].include?(value)
|
|
511
|
-
when :array then value.is_a?(Array)
|
|
512
|
-
when :object then value.is_a?(Hash)
|
|
513
|
-
else true
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
return nil if ok
|
|
517
|
-
|
|
518
|
-
shown = value.respond_to?(:keys) ? "(object)" : value.inspect
|
|
519
|
-
"parameter '#{shown}' expected type #{declared_type}"
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
def coerce_value(value, declared_type)
|
|
523
|
-
return [value, nil] if value.nil?
|
|
524
|
-
|
|
525
|
-
case declared_type.to_sym
|
|
526
|
-
when :string
|
|
527
|
-
[value.to_s, nil]
|
|
528
|
-
when :integer
|
|
529
|
-
[Integer(value), nil]
|
|
530
|
-
when :number, :float
|
|
531
|
-
[Float(value), nil]
|
|
532
|
-
when :boolean
|
|
533
|
-
case value.to_s.downcase
|
|
534
|
-
when "true" then [true, nil]
|
|
535
|
-
when "false" then [false, nil]
|
|
536
|
-
else [nil, "parameter cannot be coerced to boolean: #{value.inspect}"]
|
|
537
|
-
end
|
|
538
|
-
else
|
|
539
|
-
[value, nil]
|
|
540
|
-
end
|
|
541
|
-
rescue ArgumentError, TypeError
|
|
542
|
-
[nil, "parameter cannot be coerced to #{declared_type}: #{value.inspect}"]
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
end
|
|
547
|
-
end
|
|
548
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Agent
|
|
5
|
-
module Context
|
|
6
|
-
module Capability
|
|
7
|
-
# Routes Tool work according to the Tool execution contract.
|
|
8
|
-
#
|
|
9
|
-
# Both execution modes return {Phronomy::TaskResult}; only the execution mechanism
|
|
10
|
-
# differs.
|
|
11
|
-
#
|
|
12
|
-
# :cooperative Tool calls execute inline and must return quickly. call_async
|
|
13
|
-
# wraps their result in an already-settled TaskResult and never consumes an
|
|
14
|
-
# OffloadPool worker.
|
|
15
|
-
#
|
|
16
|
-
# :offloaded Tool calls route synchronous work through OffloadPool, whose
|
|
17
|
-
# caller-facing completion handle is also a TaskResult. Phronomy does not distinguish
|
|
18
|
-
# whether the reason is blocking I/O, CPU-bound work, or another long
|
|
19
|
-
# synchronous operation.
|
|
20
|
-
#
|
|
21
|
-
# @api private
|
|
22
|
-
module ToolExecutor
|
|
23
|
-
# @api private
|
|
24
|
-
def self.call_async(
|
|
25
|
-
tool:,
|
|
26
|
-
args:,
|
|
27
|
-
cancellation_token: nil,
|
|
28
|
-
config: {},
|
|
29
|
-
runtime: nil,
|
|
30
|
-
on_full: :raise
|
|
31
|
-
)
|
|
32
|
-
mode = tool.class.execution_mode
|
|
33
|
-
|
|
34
|
-
case mode
|
|
35
|
-
when :cooperative
|
|
36
|
-
task = Phronomy::TaskResult.deferred(name: "tool-#{tool.name}")
|
|
37
|
-
begin
|
|
38
|
-
task.complete(
|
|
39
|
-
tool.call(args, cancellation_token: cancellation_token)
|
|
40
|
-
)
|
|
41
|
-
rescue => error
|
|
42
|
-
task.fail(error)
|
|
43
|
-
end
|
|
44
|
-
task
|
|
45
|
-
when :offloaded
|
|
46
|
-
runtime ||= Phronomy::Runtime.instance
|
|
47
|
-
runtime.offload.submit(
|
|
48
|
-
cancellation_token: cancellation_token,
|
|
49
|
-
on_full: on_full
|
|
50
|
-
) do
|
|
51
|
-
tool.call(args, cancellation_token: cancellation_token)
|
|
52
|
-
end
|
|
53
|
-
else
|
|
54
|
-
raise Phronomy::ConfigurationError,
|
|
55
|
-
"unknown Tool execution_mode: #{mode.inspect}"
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Agent
|
|
5
|
-
module Context
|
|
6
|
-
module Instruction
|
|
7
|
-
# A prompt template that substitutes {{variable}} placeholders in a string.
|
|
8
|
-
#
|
|
9
|
-
# @example Simple human template
|
|
10
|
-
# t = Phronomy::Agent::Context::Instruction::PromptTemplate.new(template: "Translate to {{lang}}: {{text}}")
|
|
11
|
-
# t.format(lang: "French", text: "Hello")
|
|
12
|
-
# # => "Translate to French: Hello"
|
|
13
|
-
#
|
|
14
|
-
# @example With a system template
|
|
15
|
-
# t = Phronomy::Agent::Context::Instruction::PromptTemplate.new(
|
|
16
|
-
# template: "{{question}}",
|
|
17
|
-
# system_template: "You are a {{role}} assistant."
|
|
18
|
-
# )
|
|
19
|
-
# t.format_system(role: "helpful")
|
|
20
|
-
# # => "You are a helpful assistant."
|
|
21
|
-
#
|
|
22
|
-
# As a Runnable, #invoke accepts a Hash of variables and returns a Hash
|
|
23
|
-
# with :prompt (and optionally :system) keys.
|
|
24
|
-
class PromptTemplate
|
|
25
|
-
include Phronomy::Runnable
|
|
26
|
-
|
|
27
|
-
PLACEHOLDER = /\{\{(\w+)\}\}/
|
|
28
|
-
|
|
29
|
-
attr_reader :template, :system_template
|
|
30
|
-
|
|
31
|
-
# @param template [String] human message template with {{var}} placeholders
|
|
32
|
-
# @param system_template [String, nil] optional system message template
|
|
33
|
-
# @api public
|
|
34
|
-
def initialize(template:, system_template: nil)
|
|
35
|
-
@template = template
|
|
36
|
-
@system_template = system_template
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Substitute all {{var}} placeholders in the human template.
|
|
40
|
-
#
|
|
41
|
-
# @param variables [Hash{Symbol => String}]
|
|
42
|
-
# @return [String]
|
|
43
|
-
# @api public
|
|
44
|
-
def format(**variables)
|
|
45
|
-
substitute(@template, variables)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Substitute all {{var}} placeholders in the system template.
|
|
49
|
-
# Returns nil when no system template was set.
|
|
50
|
-
#
|
|
51
|
-
# @param variables [Hash{Symbol => String}]
|
|
52
|
-
# @return [String, nil]
|
|
53
|
-
# @api public
|
|
54
|
-
def format_system(**variables)
|
|
55
|
-
@system_template && substitute(@system_template, variables)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Runnable interface: accepts a Hash of variable values.
|
|
59
|
-
# Returns { prompt: String, system: String|nil }.
|
|
60
|
-
#
|
|
61
|
-
# @param input [Hash{Symbol => String}]
|
|
62
|
-
# @return [Hash]
|
|
63
|
-
# @api public
|
|
64
|
-
def invoke(input, config: {})
|
|
65
|
-
vars = normalize_input(input)
|
|
66
|
-
result = {prompt: format(**vars)}
|
|
67
|
-
sys = format_system(**vars)
|
|
68
|
-
result[:system] = sys if sys
|
|
69
|
-
result
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Returns the list of placeholder names found in both templates.
|
|
73
|
-
#
|
|
74
|
-
# @return [Array<Symbol>]
|
|
75
|
-
# @api public
|
|
76
|
-
def variables
|
|
77
|
-
names = @template.scan(PLACEHOLDER).flatten
|
|
78
|
-
names += @system_template.scan(PLACEHOLDER).flatten if @system_template
|
|
79
|
-
names.map(&:to_sym).uniq
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
def substitute(text, variables)
|
|
85
|
-
text.gsub(PLACEHOLDER) do |match|
|
|
86
|
-
key = Regexp.last_match(1).to_sym
|
|
87
|
-
variables.fetch(key) { raise KeyError, "Missing variable: {{#{key}}}" }
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def normalize_input(input)
|
|
92
|
-
case input
|
|
93
|
-
when Hash then input
|
|
94
|
-
when String then {input: input}
|
|
95
|
-
else raise ArgumentError, "PromptTemplate#invoke expects a Hash of variables, got #{input.class}"
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|