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,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Context
|
|
5
5
|
# ContentStore-backed durable codec boundary for one Provider input manifest.
|
|
6
6
|
# It is intentionally separate from Storage::DurableRecord.
|
|
7
7
|
class LLMInputManifest
|
|
@@ -62,7 +62,7 @@ module Phronomy
|
|
|
62
62
|
label: label
|
|
63
63
|
)
|
|
64
64
|
unless SEGMENT_DELIVERIES.include?(delivery)
|
|
65
|
-
raise Phronomy::
|
|
65
|
+
raise Phronomy::Context::ManifestError,
|
|
66
66
|
"LLMInputManifest segment delivery must be one of #{SEGMENT_DELIVERIES.inspect}, got #{delivery.inspect}"
|
|
67
67
|
end
|
|
68
68
|
tool_call_id = LLMInputManifest.send(
|
|
@@ -87,10 +87,10 @@ module Phronomy
|
|
|
87
87
|
tool_call_id: tool_call_id,
|
|
88
88
|
metadata: metadata
|
|
89
89
|
)
|
|
90
|
-
rescue Phronomy::
|
|
90
|
+
rescue Phronomy::Context::ManifestError
|
|
91
91
|
raise
|
|
92
92
|
rescue => error
|
|
93
|
-
raise Phronomy::
|
|
93
|
+
raise Phronomy::Context::ManifestError,
|
|
94
94
|
"invalid LLMInputManifest segment: #{error.class}: #{error.message}"
|
|
95
95
|
end
|
|
96
96
|
|
|
@@ -162,7 +162,7 @@ module Phronomy
|
|
|
162
162
|
label = "LLMInputManifest"
|
|
163
163
|
version = source.fetch("version")
|
|
164
164
|
unless version.is_a?(String) && version == VERSION
|
|
165
|
-
raise Phronomy::
|
|
165
|
+
raise Phronomy::Context::ManifestError,
|
|
166
166
|
"unsupported LLMInputManifest version: #{version.inspect}; " \
|
|
167
167
|
"current version is #{VERSION.inspect}"
|
|
168
168
|
end
|
|
@@ -229,10 +229,10 @@ module Phronomy
|
|
|
229
229
|
adapter_name: adapter_name,
|
|
230
230
|
adapter_version: adapter_version
|
|
231
231
|
)
|
|
232
|
-
rescue Phronomy::
|
|
232
|
+
rescue Phronomy::Context::ManifestError
|
|
233
233
|
raise
|
|
234
234
|
rescue => error
|
|
235
|
-
raise Phronomy::
|
|
235
|
+
raise Phronomy::Context::ManifestError,
|
|
236
236
|
"invalid LLMInputManifest: #{error.class}: #{error.message}"
|
|
237
237
|
end
|
|
238
238
|
|
|
@@ -262,11 +262,11 @@ module Phronomy
|
|
|
262
262
|
|
|
263
263
|
def strict_source!(hash, required:, optional:, label:)
|
|
264
264
|
unless hash.is_a?(Hash)
|
|
265
|
-
raise Phronomy::
|
|
265
|
+
raise Phronomy::Context::ManifestError,
|
|
266
266
|
"#{label} must be a Hash"
|
|
267
267
|
end
|
|
268
268
|
unless hash.keys.all? { |key| key.is_a?(String) }
|
|
269
|
-
raise Phronomy::
|
|
269
|
+
raise Phronomy::Context::ManifestError,
|
|
270
270
|
"#{label} keys must all be String"
|
|
271
271
|
end
|
|
272
272
|
|
|
@@ -277,13 +277,13 @@ module Phronomy
|
|
|
277
277
|
details = []
|
|
278
278
|
details << "missing=#{missing.inspect}" unless missing.empty?
|
|
279
279
|
details << "unknown=#{unknown.inspect}" unless unknown.empty?
|
|
280
|
-
raise Phronomy::
|
|
280
|
+
raise Phronomy::Context::ManifestError,
|
|
281
281
|
"#{label} schema mismatch (#{details.join(", ")})"
|
|
282
282
|
end
|
|
283
283
|
Phronomy::CanonicalJSON.dump(hash)
|
|
284
284
|
hash
|
|
285
285
|
rescue ArgumentError => error
|
|
286
|
-
raise Phronomy::
|
|
286
|
+
raise Phronomy::Context::ManifestError,
|
|
287
287
|
"#{label} is not canonical JSON compatible: #{error.message}"
|
|
288
288
|
end
|
|
289
289
|
|
|
@@ -291,7 +291,7 @@ module Phronomy
|
|
|
291
291
|
value = hash.fetch(key)
|
|
292
292
|
return value if value.is_a?(Integer)
|
|
293
293
|
|
|
294
|
-
raise Phronomy::
|
|
294
|
+
raise Phronomy::Context::ManifestError,
|
|
295
295
|
"#{label} #{key} must be an Integer"
|
|
296
296
|
end
|
|
297
297
|
|
|
@@ -299,7 +299,7 @@ module Phronomy
|
|
|
299
299
|
value = hash.fetch(key)
|
|
300
300
|
return value if value.is_a?(Integer) && value.positive?
|
|
301
301
|
|
|
302
|
-
raise Phronomy::
|
|
302
|
+
raise Phronomy::Context::ManifestError,
|
|
303
303
|
"#{label} #{key} must be a positive Integer"
|
|
304
304
|
end
|
|
305
305
|
|
|
@@ -307,7 +307,7 @@ module Phronomy
|
|
|
307
307
|
value = hash.fetch(key)
|
|
308
308
|
return value if value.is_a?(Integer) && value >= 0
|
|
309
309
|
|
|
310
|
-
raise Phronomy::
|
|
310
|
+
raise Phronomy::Context::ManifestError,
|
|
311
311
|
"#{label} #{key} must be a non-negative Integer"
|
|
312
312
|
end
|
|
313
313
|
|
|
@@ -315,7 +315,7 @@ module Phronomy
|
|
|
315
315
|
value = hash.fetch(key)
|
|
316
316
|
return value if value.is_a?(String) && !value.empty?
|
|
317
317
|
|
|
318
|
-
raise Phronomy::
|
|
318
|
+
raise Phronomy::Context::ManifestError,
|
|
319
319
|
"#{label} #{key} must be a non-empty String"
|
|
320
320
|
end
|
|
321
321
|
|
|
@@ -323,7 +323,7 @@ module Phronomy
|
|
|
323
323
|
value = hash[key]
|
|
324
324
|
return value if value.nil? || value.is_a?(String)
|
|
325
325
|
|
|
326
|
-
raise Phronomy::
|
|
326
|
+
raise Phronomy::Context::ManifestError,
|
|
327
327
|
"#{label} #{key} must be a String or nil"
|
|
328
328
|
end
|
|
329
329
|
|
|
@@ -331,7 +331,7 @@ module Phronomy
|
|
|
331
331
|
value = hash.fetch(key)
|
|
332
332
|
return value if value.is_a?(String) && allowed.include?(value)
|
|
333
333
|
|
|
334
|
-
raise Phronomy::
|
|
334
|
+
raise Phronomy::Context::ManifestError,
|
|
335
335
|
"#{label} #{key} must be one of #{allowed.inspect}"
|
|
336
336
|
end
|
|
337
337
|
|
|
@@ -339,7 +339,7 @@ module Phronomy
|
|
|
339
339
|
value = hash.fetch(key)
|
|
340
340
|
return value if value.is_a?(Array)
|
|
341
341
|
|
|
342
|
-
raise Phronomy::
|
|
342
|
+
raise Phronomy::Context::ManifestError,
|
|
343
343
|
"#{label} #{key} must be an Array"
|
|
344
344
|
end
|
|
345
345
|
|
|
@@ -347,7 +347,7 @@ module Phronomy
|
|
|
347
347
|
value = hash.fetch(key)
|
|
348
348
|
return value if value.is_a?(Hash)
|
|
349
349
|
|
|
350
|
-
raise Phronomy::
|
|
350
|
+
raise Phronomy::Context::ManifestError,
|
|
351
351
|
"#{label} #{key} must be a Hash"
|
|
352
352
|
end
|
|
353
353
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Context
|
|
5
5
|
# Typed, canonicalizable input customization returned by before_llm_input.
|
|
6
6
|
# v1 deliberately exposes only fields that are fully applied to every call.
|
|
7
7
|
LLMInputPatch = Data.define(:model_config_patch, :segment_candidates) do
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Context
|
|
5
|
+
# A prompt template that substitutes {{variable}} placeholders in a string.
|
|
6
|
+
#
|
|
7
|
+
# @example Simple human template
|
|
8
|
+
# t = Phronomy::Context::PromptTemplate.new(template: "Translate to {{lang}}: {{text}}")
|
|
9
|
+
# t.format(lang: "French", text: "Hello")
|
|
10
|
+
# # => "Translate to French: Hello"
|
|
11
|
+
#
|
|
12
|
+
# @example With a system template
|
|
13
|
+
# t = Phronomy::Context::PromptTemplate.new(
|
|
14
|
+
# template: "{{question}}",
|
|
15
|
+
# system_template: "You are a {{role}} assistant."
|
|
16
|
+
# )
|
|
17
|
+
# t.format_system(role: "helpful")
|
|
18
|
+
# # => "You are a helpful assistant."
|
|
19
|
+
#
|
|
20
|
+
# As a Runnable, #invoke accepts a Hash of variables and returns a Hash
|
|
21
|
+
# with :prompt (and optionally :system) keys.
|
|
22
|
+
class PromptTemplate
|
|
23
|
+
include Phronomy::Runnable
|
|
24
|
+
|
|
25
|
+
PLACEHOLDER = /\{\{(\w+)\}\}/
|
|
26
|
+
|
|
27
|
+
attr_reader :template, :system_template
|
|
28
|
+
|
|
29
|
+
# @param template [String] human message template with {{var}} placeholders
|
|
30
|
+
# @param system_template [String, nil] optional system message template
|
|
31
|
+
# @api public
|
|
32
|
+
def initialize(template:, system_template: nil)
|
|
33
|
+
@template = template
|
|
34
|
+
@system_template = system_template
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Substitute all {{var}} placeholders in the human template.
|
|
38
|
+
#
|
|
39
|
+
# @param variables [Hash{Symbol => String}]
|
|
40
|
+
# @return [String]
|
|
41
|
+
# @api public
|
|
42
|
+
def format(**variables)
|
|
43
|
+
substitute(@template, variables)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Substitute all {{var}} placeholders in the system template.
|
|
47
|
+
# Returns nil when no system template was set.
|
|
48
|
+
#
|
|
49
|
+
# @param variables [Hash{Symbol => String}]
|
|
50
|
+
# @return [String, nil]
|
|
51
|
+
# @api public
|
|
52
|
+
def format_system(**variables)
|
|
53
|
+
@system_template && substitute(@system_template, variables)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Runnable interface: accepts a Hash of variable values.
|
|
57
|
+
# Returns { prompt: String, system: String|nil }.
|
|
58
|
+
#
|
|
59
|
+
# @param input [Hash{Symbol => String}]
|
|
60
|
+
# @return [Hash]
|
|
61
|
+
# @api public
|
|
62
|
+
def invoke(input, config: {})
|
|
63
|
+
vars = normalize_input(input)
|
|
64
|
+
result = {prompt: format(**vars)}
|
|
65
|
+
sys = format_system(**vars)
|
|
66
|
+
result[:system] = sys if sys
|
|
67
|
+
result
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Returns the list of placeholder names found in both templates.
|
|
71
|
+
#
|
|
72
|
+
# @return [Array<Symbol>]
|
|
73
|
+
# @api public
|
|
74
|
+
def variables
|
|
75
|
+
names = @template.scan(PLACEHOLDER).flatten
|
|
76
|
+
names += @system_template.scan(PLACEHOLDER).flatten if @system_template
|
|
77
|
+
names.map(&:to_sym).uniq
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def substitute(text, variables)
|
|
83
|
+
text.gsub(PLACEHOLDER) do |match|
|
|
84
|
+
key = Regexp.last_match(1).to_sym
|
|
85
|
+
variables.fetch(key) { raise KeyError, "Missing variable: {{#{key}}}" }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def normalize_input(input)
|
|
90
|
+
case input
|
|
91
|
+
when Hash then input
|
|
92
|
+
when String then {input: input}
|
|
93
|
+
else raise ArgumentError, "PromptTemplate#invoke expects a Hash of variables, got #{input.class}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "csv"
|
|
4
4
|
|
|
5
5
|
module Phronomy
|
|
6
|
-
module
|
|
6
|
+
module Documents
|
|
7
7
|
module Loader
|
|
8
8
|
# Loads a CSV file, converting each row into a separate document.
|
|
9
9
|
#
|
|
@@ -12,7 +12,7 @@ module Phronomy
|
|
|
12
12
|
# a human-readable "key: value" string for embedding.
|
|
13
13
|
#
|
|
14
14
|
# @example
|
|
15
|
-
# loader = Phronomy::
|
|
15
|
+
# loader = Phronomy::Documents::Loader::CsvLoader.new
|
|
16
16
|
# docs = loader.load("products.csv")
|
|
17
17
|
# # => [
|
|
18
18
|
# # { text: "name: Widget\nprice: 9.99", metadata: { source: "...", row: 1, name: "Widget", price: "9.99" } },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Documents
|
|
5
5
|
module Loader
|
|
6
6
|
# Loads a Markdown file, optionally splitting on top-level headings.
|
|
7
7
|
#
|
|
@@ -10,12 +10,12 @@ module Phronomy
|
|
|
10
10
|
# rather than the full file at once.
|
|
11
11
|
#
|
|
12
12
|
# @example Single document (heading split disabled)
|
|
13
|
-
# loader = Phronomy::
|
|
13
|
+
# loader = Phronomy::Documents::Loader::MarkdownLoader.new(split_on_headings: false)
|
|
14
14
|
# docs = loader.load("README.md")
|
|
15
15
|
# # => [{ text: "# Title\n...", metadata: { source: "README.md" } }]
|
|
16
16
|
#
|
|
17
17
|
# @example Split per heading (default)
|
|
18
|
-
# loader = Phronomy::
|
|
18
|
+
# loader = Phronomy::Documents::Loader::MarkdownLoader.new
|
|
19
19
|
# docs = loader.load("guide.md")
|
|
20
20
|
# # => [
|
|
21
21
|
# # { text: "# Section 1\n...", metadata: { source: "guide.md", section: "Section 1" } },
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Documents
|
|
5
5
|
module Loader
|
|
6
6
|
# Loads a plain-text file as a single document.
|
|
7
7
|
#
|
|
8
8
|
# @example
|
|
9
|
-
# loader = Phronomy::
|
|
9
|
+
# loader = Phronomy::Documents::Loader::PlainTextLoader.new
|
|
10
10
|
# docs = loader.load("/path/to/file.txt")
|
|
11
11
|
# # => [{ text: "...", metadata: { source: "/path/to/file.txt" } }]
|
|
12
12
|
class PlainTextLoader < Base
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Documents
|
|
5
5
|
module Splitter
|
|
6
6
|
# Splits text into fixed-size character chunks with optional overlap.
|
|
7
7
|
#
|
|
8
8
|
# @example
|
|
9
|
-
# splitter = Phronomy::
|
|
9
|
+
# splitter = Phronomy::Documents::Splitter::FixedSizeSplitter.new(chunk_size: 200, chunk_overlap: 20)
|
|
10
10
|
# chunks = splitter.split({ text: long_text, metadata: { source: "doc.txt" } })
|
|
11
11
|
# # => [
|
|
12
12
|
# # { text: "...(200 chars)...", metadata: { source: "doc.txt", chunk: 0 } },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
|
-
module
|
|
4
|
+
module Documents
|
|
5
5
|
module Splitter
|
|
6
6
|
# Splits text recursively using a prioritised list of separator strings.
|
|
7
7
|
#
|
|
@@ -18,7 +18,7 @@ module Phronomy
|
|
|
18
18
|
# 5. "" — character-level fallback
|
|
19
19
|
#
|
|
20
20
|
# @example
|
|
21
|
-
# splitter = Phronomy::
|
|
21
|
+
# splitter = Phronomy::Documents::Splitter::RecursiveSplitter.new(chunk_size: 300, chunk_overlap: 30)
|
|
22
22
|
# chunks = splitter.split({ text: long_markdown, metadata: { source: "guide.md" } })
|
|
23
23
|
class RecursiveSplitter < Base
|
|
24
24
|
DEFAULT_SEPARATORS = ["\n\n", "\n", ". ", " ", ""].freeze
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Embeddings
|
|
5
|
+
# Framework-owned asynchronous execution of a synchronous embedding adapter.
|
|
6
|
+
#
|
|
7
|
+
# Construction starts no Runtime. Each operation uses the current default
|
|
8
|
+
# pool unless a caller-owned pool was injected. Timeout includes queue wait
|
|
9
|
+
# and settles the result without forcibly interrupting an executing adapter.
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
class AsyncClient
|
|
13
|
+
# @param adapter [Embeddings::Base] synchronous embedding adapter
|
|
14
|
+
# @param pool [Concurrency::OffloadPool, nil] optional execution pool
|
|
15
|
+
# @api public
|
|
16
|
+
def initialize(adapter:, pool: nil)
|
|
17
|
+
@adapter = adapter
|
|
18
|
+
@pool = pool
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Submits a synchronous embed call without waiting for queue capacity.
|
|
22
|
+
#
|
|
23
|
+
# @param text [String]
|
|
24
|
+
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
|
|
25
|
+
# @param timeout [Numeric, nil] operation-wide submit timeout
|
|
26
|
+
# @return [Phronomy::TaskResult] the pool's original completion handle
|
|
27
|
+
# @api public
|
|
28
|
+
def embed_async(text, cancellation_token = nil, timeout: nil)
|
|
29
|
+
Phronomy::Execution.submit(pool: default_pool,
|
|
30
|
+
timeout: timeout,
|
|
31
|
+
cancellation_token: cancellation_token,
|
|
32
|
+
on_full: :raise) do
|
|
33
|
+
@adapter.embed(text, cancellation_token)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def default_pool
|
|
40
|
+
@pool
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "transport_error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module Embeddings
|
|
7
|
+
# Provider refusal; this classification alone does not authorize retries.
|
|
8
|
+
# @api public
|
|
9
|
+
class AuthenticationError < TransportError; end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
module Embeddings
|
|
5
|
+
# Embeddings adapter backed by RubyLLM.
|
|
6
|
+
#
|
|
7
|
+
# Delegates to +RubyLLM.embed+ and returns the resulting vector as an
|
|
8
|
+
# +Array<Float>+.
|
|
9
|
+
#
|
|
10
|
+
# @example Default model
|
|
11
|
+
# embeddings = Phronomy::Embeddings::RubyLLMEmbeddings.new
|
|
12
|
+
# vector = embeddings.embed("Hello, world!")
|
|
13
|
+
#
|
|
14
|
+
# @example Explicit model
|
|
15
|
+
# embeddings = Phronomy::Embeddings::RubyLLMEmbeddings.new(model: "text-embedding-3-small")
|
|
16
|
+
# vector = embeddings.embed("Hello, world!")
|
|
17
|
+
class RubyLLMEmbeddings < Base
|
|
18
|
+
# @param model [String, nil] embedding model identifier; nil uses the RubyLLM default
|
|
19
|
+
# @param provider [Symbol, nil] provider override (e.g. :openai); nil uses the RubyLLM default
|
|
20
|
+
# @param assume_model_exists [Boolean] when true, skips RubyLLM model-registry validation
|
|
21
|
+
# (useful for locally hosted models not in the registry)
|
|
22
|
+
# @api public
|
|
23
|
+
def initialize(model: nil, provider: nil, assume_model_exists: false)
|
|
24
|
+
@model = model
|
|
25
|
+
@provider = provider
|
|
26
|
+
@assume_model_exists = assume_model_exists
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
# Embed text via RubyLLM.
|
|
32
|
+
#
|
|
33
|
+
# @param text [String]
|
|
34
|
+
# @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil] optional; raises CancellationError when cancelled
|
|
35
|
+
# @return [Array<Float>]
|
|
36
|
+
# @api public
|
|
37
|
+
def perform_embed(text, cancellation_token = nil)
|
|
38
|
+
opts = {}
|
|
39
|
+
opts[:model] = @model if @model
|
|
40
|
+
opts[:provider] = @provider if @provider
|
|
41
|
+
opts[:assume_model_exists] = true if @assume_model_exists
|
|
42
|
+
::RubyLLM.embed(text, **opts).vectors
|
|
43
|
+
rescue ::RubyLLM::UnauthorizedError, ::RubyLLM::ForbiddenError => error
|
|
44
|
+
raise AuthenticationError.new(error.message, code: "embeddings.authentication_failed"), cause: error
|
|
45
|
+
rescue ::RubyLLM::RateLimitError => error
|
|
46
|
+
raise RateLimitError.new(error.message, code: "embeddings.rate_limited"), cause: error
|
|
47
|
+
rescue ::RubyLLM::Error => error
|
|
48
|
+
raise TransportError.new(error.message), cause: error
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "invalid_result_error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module Embeddings
|
|
7
|
+
# Owns input validation, the cancellation checkpoint and result validation.
|
|
8
|
+
# Providers implement perform_embed; execution belongs to AsyncClient.
|
|
9
|
+
# This contract selects no provider or vector store.
|
|
10
|
+
# @api public
|
|
11
|
+
class Base
|
|
12
|
+
# @param text [String] empty text is allowed; model restrictions are provider-owned
|
|
13
|
+
# @param cancellation_token [#raise_if_cancelled!, nil]
|
|
14
|
+
# @return [Array<Float>] non-empty finite vector
|
|
15
|
+
# @raise [ArgumentError] when input is not text
|
|
16
|
+
# @raise [InvalidResultError] when the provider returns a malformed vector
|
|
17
|
+
# @api public
|
|
18
|
+
def embed(text, cancellation_token = nil)
|
|
19
|
+
cancellation_token&.raise_if_cancelled!
|
|
20
|
+
raise ArgumentError, "text must be a String" unless text.is_a?(String)
|
|
21
|
+
vector = perform_embed(text, cancellation_token)
|
|
22
|
+
unless vector.is_a?(Array) && !vector.empty? && vector.all? { |value|
|
|
23
|
+
value.is_a?(Numeric) && value.real? && value.finite? && value.to_f.finite?
|
|
24
|
+
}
|
|
25
|
+
raise InvalidResultError, "embed must return a non-empty Array of finite real numbers"
|
|
26
|
+
end
|
|
27
|
+
vector.map(&:to_f)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
# Provider extension point. Preserve cancellation and application errors;
|
|
33
|
+
# SDK adapters translate their own provider errors to TransportError.
|
|
34
|
+
# @param text [String]
|
|
35
|
+
# @param cancellation_token [#raise_if_cancelled!, nil]
|
|
36
|
+
# @return [Array<Numeric>]
|
|
37
|
+
# @api public
|
|
38
|
+
def perform_embed(text, cancellation_token = nil)
|
|
39
|
+
raise NotImplementedError, "#{self.class}#perform_embed is not implemented"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../common/error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module Embeddings
|
|
7
|
+
# A provider returned data that violates the embedding result contract.
|
|
8
|
+
# @api public
|
|
9
|
+
class InvalidResultError < Phronomy::Error; end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "transport_error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module Embeddings
|
|
7
|
+
# Provider refusal; this classification alone does not authorize retries.
|
|
8
|
+
# @api public
|
|
9
|
+
class RateLimitError < TransportError; end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../common/error"
|
|
4
|
+
|
|
5
|
+
module Phronomy
|
|
6
|
+
module Embeddings
|
|
7
|
+
# An embedding provider failed; the original SDK exception remains #cause.
|
|
8
|
+
# @api public
|
|
9
|
+
class TransportError < Phronomy::Error; end
|
|
10
|
+
end
|
|
11
|
+
end
|