phronomy 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +9 -3
- data/benchmark/bench_agent_invoke.rb +25 -50
- data/benchmark/bench_context_assembler.rb +14 -11
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
- data/docs/architecture/agent-transition-ownership.md +13 -89
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +3 -3
- data/docs/architecture/context-management.md +1 -1
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +6 -0
- data/docs/architecture/multi-agent-handoff.md +6 -5
- data/docs/architecture/persistence.md +27 -9
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +10 -1
- data/docs/architecture/remaining-refactoring-plan.md +16 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +6 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
- data/docs/architecture.md +24 -11
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
- data/docs/decisions/032-storage-backend-composition.md +5 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
- data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
- data/docs/decisions/040-configuration-default-composition.md +12 -1
- data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
- data/docs/decisions/058-neutral-storage-primitives.md +5 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +18 -1
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/features.md +8 -3
- data/docs/getting-started.md +9 -6
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
- data/docs/migrations/handoff-runner-multi-agent.md +2 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +37 -32
- data/lib/phronomy/agent/base.rb +74 -72
- data/lib/phronomy/agent/before_llm_input.rb +64 -0
- data/lib/phronomy/agent/composition/run_once.rb +1 -1
- data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
- data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
- data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
- data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
- data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
- data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
- data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
- data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
- data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +182 -0
- data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
- data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
- data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
- data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
- data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +1 -21
- data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
- data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
- data/lib/phronomy/agent/persistence/watermark.rb +13 -11
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
- data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/storage_schema.rb +1 -0
- data/lib/phronomy/content_store/stored_contents.rb +2 -1
- data/lib/phronomy/context/assembly.rb +202 -0
- data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
- data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
- data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/engine/diagnostics.rb +1 -1
- data/lib/phronomy/engine/event_loop.rb +7 -7
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +1 -6
- data/lib/phronomy/engine/fsm_session.rb +3 -3
- data/lib/phronomy/engine/metrics.rb +16 -14
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +25 -12
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/{engine → execution}/execution.rb +61 -27
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
- data/lib/phronomy/generation/generator_verifier.rb +7 -7
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/multi_agent/shared_state.rb +2 -2
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
- data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +8 -2
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +549 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/tool/tool_executor.rb +58 -0
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +1 -1
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/workflow/execution/workflow.rb +7 -7
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
- data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +57 -16
- data/scripts/api_snapshot.rb +35 -15
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent.rbs +14 -138
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +17 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +0 -21
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent.rbs +6 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +1 -99
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
- data/sig/phronomy/tool.rbs +48 -4
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +1 -1
- data/sig/phronomy.rbs +0 -49
- metadata +318 -117
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -548
- data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
- data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
- data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
- data/lib/phronomy/agent/persistence/queries.rb +0 -61
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration/configuration.rb +0 -68
- data/lib/phronomy/configuration/global_configuration.rb +0 -26
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/engine/execution_receiver.rb +0 -65
- data/lib/phronomy/engine/runnable.rb +0 -54
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/llm_contract/token_usage.rb +0 -85
- data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
- data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
- data/lib/phronomy/persistence/api/persistence.rb +0 -140
- data/lib/phronomy/persistence_composition/repositories.rb +0 -77
- data/lib/phronomy/recovery/recovery.rb +0 -186
- data/lib/phronomy/tool/contract/tool_error.rb +0 -7
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
- data/sig/phronomy/execution_receiver.rbs +0 -34
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
- /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
- /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Concurrency
|
|
5
|
-
# Represents a bounded execution scope that owns a {CancellationToken} and
|
|
6
|
-
# optionally a {Deadline}.
|
|
7
|
-
#
|
|
8
|
-
# +CancellationScope+ replaces ad-hoc +Timeout.timeout+ calls in agent and
|
|
9
|
-
# tool code. All work performed within a scope should observe the scope's
|
|
10
|
-
# token; when the scope is cancelled (explicitly or by deadline expiry) the
|
|
11
|
-
# token is cancelled and all child tasks that check it will stop.
|
|
12
|
-
#
|
|
13
|
-
# @example Time-bounded invocation
|
|
14
|
-
# scope = Phronomy::Concurrency::CancellationScope.new.deadline_in(30)
|
|
15
|
-
# result = scope.pop_queue(completion_queue) do
|
|
16
|
-
# raise Phronomy::TimeoutError, "timed out"
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
# @example Explicit cancellation
|
|
20
|
-
# scope = Phronomy::Concurrency::CancellationScope.new
|
|
21
|
-
# operation = Phronomy::Runtime.instance.offload.submit(
|
|
22
|
-
# cancellation_token: scope.token
|
|
23
|
-
# ) { synchronous_operation }
|
|
24
|
-
# scope.cancel! if some_condition
|
|
25
|
-
class CancellationScope
|
|
26
|
-
# @return [CancellationToken] the token owned by this scope
|
|
27
|
-
attr_reader :token
|
|
28
|
-
|
|
29
|
-
# @return [Deadline, nil] the deadline attached to this scope, if any
|
|
30
|
-
attr_reader :deadline
|
|
31
|
-
|
|
32
|
-
# @param parent_token [CancellationToken, nil] when provided, cancellation of
|
|
33
|
-
# the parent token is propagated to this scope's token via a callback
|
|
34
|
-
# (for explicit cancel) and/or the Runtime timer queue (for monotonic
|
|
35
|
-
# deadline expiry). No polling thread is spawned.
|
|
36
|
-
# @api private
|
|
37
|
-
def initialize(parent_token: nil)
|
|
38
|
-
@token = Phronomy::Concurrency::CancellationToken.new
|
|
39
|
-
@deadline = nil
|
|
40
|
-
|
|
41
|
-
if parent_token
|
|
42
|
-
# Propagate explicit cancel() from parent to child via callback.
|
|
43
|
-
parent_token.on_cancel { @token.cancel! }
|
|
44
|
-
|
|
45
|
-
# Propagate monotonic-deadline expiry from parent to child via the
|
|
46
|
-
# timer queue (avoids a polling thread).
|
|
47
|
-
remaining = parent_token.remaining_monotonic_seconds
|
|
48
|
-
if !remaining.nil?
|
|
49
|
-
if remaining <= 0
|
|
50
|
-
@token.cancel!
|
|
51
|
-
else
|
|
52
|
-
Phronomy::Runtime.instance.timer_queue.schedule(seconds: remaining) do
|
|
53
|
-
@token.cancel!
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Attaches a deadline that will cancel this scope after +seconds+.
|
|
61
|
-
#
|
|
62
|
-
# @param seconds [Numeric] timeout duration
|
|
63
|
-
# @return [self]
|
|
64
|
-
# @api private
|
|
65
|
-
def deadline_in(seconds)
|
|
66
|
-
@deadline = Phronomy::Concurrency::Deadline.in(seconds)
|
|
67
|
-
@deadline.attach_to(@token)
|
|
68
|
-
self
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Cancels this scope immediately.
|
|
72
|
-
# @return [void]
|
|
73
|
-
# @api private
|
|
74
|
-
def cancel!
|
|
75
|
-
@token.cancel!
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Returns +true+ if this scope has been cancelled.
|
|
79
|
-
# @return [Boolean]
|
|
80
|
-
# @api private
|
|
81
|
-
def cancelled?
|
|
82
|
-
@token.cancelled?
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Returns the remaining time in seconds before the deadline expires,
|
|
86
|
-
# or +nil+ when no deadline is set.
|
|
87
|
-
# @return [Float, nil]
|
|
88
|
-
# @api private
|
|
89
|
-
def remaining_seconds
|
|
90
|
-
@deadline&.remaining_seconds
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Pops from +queue+ with a timeout derived from the attached deadline (or
|
|
94
|
-
# +fallback_timeout+ seconds when no deadline is set). If the pop times out,
|
|
95
|
-
# the scope is cancelled and the block is called (or a {TimeoutError} raised).
|
|
96
|
-
#
|
|
97
|
-
# @param queue [Phronomy::Concurrency::AsyncQueue] the queue to pop from
|
|
98
|
-
# @param fallback_timeout [Numeric, nil] used when no deadline is attached
|
|
99
|
-
# @yield called when the operation times out
|
|
100
|
-
# @raise [Phronomy::TimeoutError] when no block is given and a timeout occurs
|
|
101
|
-
# @return [Object] the popped value
|
|
102
|
-
# @api private
|
|
103
|
-
def pop_queue(queue, fallback_timeout: nil)
|
|
104
|
-
timeout = @deadline&.remaining_seconds || fallback_timeout
|
|
105
|
-
result = if timeout
|
|
106
|
-
queue.pop(timeout: timeout)
|
|
107
|
-
else
|
|
108
|
-
queue.pop
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
if result.nil?
|
|
112
|
-
cancel!
|
|
113
|
-
if block_given?
|
|
114
|
-
yield
|
|
115
|
-
else
|
|
116
|
-
raise Phronomy::TimeoutError, "CancellationScope timed out"
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
result
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module Concurrency
|
|
5
|
-
# Connects explicit invocation controls before operation admission. Its token
|
|
6
|
-
# is private: cancelling it never cancels the application's shared tokens.
|
|
7
|
-
# Used by Agent, Blocking and Orchestrator admission; it owns no worker.
|
|
8
|
-
# @api private
|
|
9
|
-
class OperationBinding
|
|
10
|
-
attr_reader :token, :scope
|
|
11
|
-
|
|
12
|
-
def initialize(invocation_context:, cancellation_token:)
|
|
13
|
-
if !invocation_context.nil? && !invocation_context.is_a?(InvocationContext)
|
|
14
|
-
raise TypeError, "invocation_context must be a Phronomy::InvocationContext or nil"
|
|
15
|
-
end
|
|
16
|
-
@scope = invocation_context&.__execution_scope
|
|
17
|
-
@token = CancellationToken.new
|
|
18
|
-
@subscriptions = Subscriptions.new
|
|
19
|
-
[invocation_context&.cancellation_token, cancellation_token].compact.uniq.each do |source|
|
|
20
|
-
@subscriptions.cancellation(source) { @token.cancel! }
|
|
21
|
-
end
|
|
22
|
-
if !@scope && invocation_context&.deadline
|
|
23
|
-
@subscriptions.after(invocation_context.deadline.remaining_seconds) { @token.cancel! }
|
|
24
|
-
end
|
|
25
|
-
@token.cancel! if @scope && !@scope.__open?
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def bind(result)
|
|
29
|
-
result.__bind_execution(@scope)
|
|
30
|
-
track(result)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def track(result)
|
|
34
|
-
@subscriptions.result(result) { @subscriptions.close }
|
|
35
|
-
result
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def close
|
|
39
|
-
@subscriptions.close
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
# Internal lifecycle/delivery contract for feature-owned execution state.
|
|
5
|
-
# Receivers are retained by one EventLoop, not an application callback SPI.
|
|
6
|
-
# Normal mutation and delivery run only on that loop. idle? runs with its
|
|
7
|
-
# lifecycle lock held; it must not call Runtime or acquire that lock again.
|
|
8
|
-
# shutdown runs on a failing loop, or exclusively after a clean loop joins.
|
|
9
|
-
# @api private
|
|
10
|
-
class ExecutionReceiver
|
|
11
|
-
def self.for(event_loop)
|
|
12
|
-
event_loop.__execution_receiver(key: self) ||
|
|
13
|
-
event_loop.__register_execution_receiver(key: self, receiver: new(event_loop: event_loop))
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Lookup only: neither a loop nor a receiver is created during inspection.
|
|
17
|
-
def self.existing_for(runtime)
|
|
18
|
-
runtime.__event_loop_if_initialized&.__execution_receiver(key: self)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def initialize(event_loop:)
|
|
22
|
-
@event_loop = event_loop
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def __bound_to?(event_loop)
|
|
26
|
-
@event_loop.equal?(event_loop)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def idle?
|
|
30
|
-
raise NotImplementedError
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def deliver(message)
|
|
34
|
-
raise NotImplementedError
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def shutdown(error:)
|
|
38
|
-
raise NotImplementedError
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def session_retired(fsm_session_id, reason:)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
def synchronize(&block)
|
|
47
|
-
@event_loop.__synchronize_execution_state(&block)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def admit(&block)
|
|
51
|
-
@event_loop.__admit_execution(self, &block)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def post_message(message, admission: false, completion: nil)
|
|
55
|
-
@event_loop.__post_execution(self, message, admission: admission, completion: completion)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def assert_event_loop_thread!
|
|
59
|
-
return if @event_loop.current?
|
|
60
|
-
|
|
61
|
-
raise Phronomy::Error,
|
|
62
|
-
"Phronomy-managed live execution state may only be mutated on EventLoop"
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
# Base interface for executable graph components.
|
|
5
|
-
# Provides invoke / stream / batch.
|
|
6
|
-
module Runnable
|
|
7
|
-
# Synchronous execution. Must be overridden in subclasses.
|
|
8
|
-
def invoke(input, config: {})
|
|
9
|
-
raise NotImplementedError, "#{self.class}#invoke is not implemented"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Streaming execution. Default yields the invoke result as a single chunk.
|
|
13
|
-
def stream(input, config: {}, &block)
|
|
14
|
-
result = invoke(input, config: config)
|
|
15
|
-
yield result if block
|
|
16
|
-
result
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Batch execution. Default calls invoke sequentially.
|
|
20
|
-
def batch(inputs, config: {})
|
|
21
|
-
inputs.map { |input| invoke(input, config: config) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Convenience wrapper that delegates to the global tracer.
|
|
25
|
-
# Yields a span; the block must return [result, usage] where usage is a
|
|
26
|
-
# Phronomy::TokenUsage or nil. Returns only the result value.
|
|
27
|
-
#
|
|
28
|
-
# When +trace_pii+ is disabled, both the input and the output (LLM response,
|
|
29
|
-
# tool result) are replaced with the literal string "[REDACTED]" before being
|
|
30
|
-
# forwarded to the tracing backend. The actual result is still returned to
|
|
31
|
-
# the caller — only the copy sent to the tracer is redacted.
|
|
32
|
-
#
|
|
33
|
-
# @example
|
|
34
|
-
# trace("my_chain", input: input) { [invoke(input), nil] }
|
|
35
|
-
# @api public
|
|
36
|
-
def trace(name, input: nil, **meta, &block)
|
|
37
|
-
traced_input = Phronomy.configuration.trace_pii ? input : "[REDACTED]"
|
|
38
|
-
|
|
39
|
-
if Phronomy.configuration.trace_pii
|
|
40
|
-
# PII recording is allowed: pass through unchanged.
|
|
41
|
-
Phronomy.configuration.tracer.trace(name, input: traced_input, **meta, &block)
|
|
42
|
-
else
|
|
43
|
-
# Redact both input (above) and output before forwarding to the tracer.
|
|
44
|
-
# Capture the real result so callers receive the unredacted value.
|
|
45
|
-
real_result = nil
|
|
46
|
-
Phronomy.configuration.tracer.trace(name, input: traced_input, **meta) do |span|
|
|
47
|
-
real_result, usage = block.call(span)
|
|
48
|
-
["[REDACTED]", usage]
|
|
49
|
-
end
|
|
50
|
-
real_result
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module LLMAdapter
|
|
5
|
-
# Default LLMAdapter SPI implementation backed by RubyLLM.
|
|
6
|
-
#
|
|
7
|
-
# The synchronous +chat.ask+ / +chat.complete+ calls are invoked through the
|
|
8
|
-
# framework-owned async bridge in {LLMAdapter::Base}, so adapter consumers do
|
|
9
|
-
# not need to manage OffloadPool themselves.
|
|
10
|
-
#
|
|
11
|
-
# @example Explicitly configuring this adapter
|
|
12
|
-
# Phronomy.configure do |c|
|
|
13
|
-
# c.llm_adapter = Phronomy::LLMAdapter::RubyLLM.new
|
|
14
|
-
# end
|
|
15
|
-
#
|
|
16
|
-
# @api public
|
|
17
|
-
class RubyLLM < Base
|
|
18
|
-
# Delegates to +chat.ask(message)+ or +chat.complete+ when message is nil.
|
|
19
|
-
#
|
|
20
|
-
# Passing +nil+ for +message+ is used by the ReAct loop for continuation
|
|
21
|
-
# turns where the user message has already been added to the chat history
|
|
22
|
-
# (for example after a Tool result).
|
|
23
|
-
#
|
|
24
|
-
# @param chat [Object] RubyLLM chat session
|
|
25
|
-
# @param message [String, nil] user message, or nil to continue the chat
|
|
26
|
-
# @param config [Hash] invocation config (not used directly here)
|
|
27
|
-
# @return [Object] RubyLLM response
|
|
28
|
-
# @api public
|
|
29
|
-
def complete(chat, message, config: {})
|
|
30
|
-
message ? chat.ask(message) : chat.complete
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Delegates to +chat.ask(message) { |chunk| ... }+ or +chat.complete(&block)+
|
|
34
|
-
# when message is nil.
|
|
35
|
-
#
|
|
36
|
-
# @param chat [Object] RubyLLM chat session
|
|
37
|
-
# @param message [String, nil] user message, or nil to continue the chat
|
|
38
|
-
# @param config [Hash] invocation config
|
|
39
|
-
# @yield [chunk] streaming chunk forwarded from RubyLLM
|
|
40
|
-
# @return [Object] RubyLLM response
|
|
41
|
-
# @api public
|
|
42
|
-
def stream(chat, message, config: {}, &block)
|
|
43
|
-
message ? chat.ask(message, &block) : chat.complete(&block)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
# Immutable value object that holds token usage counts for a single LLM call
|
|
5
|
-
# or an accumulated total across multiple calls.
|
|
6
|
-
#
|
|
7
|
-
# Fields mirror the values reported by RubyLLM::Tokens:
|
|
8
|
-
#
|
|
9
|
-
# input - tokens consumed by the input (prompt)
|
|
10
|
-
# output - tokens produced by the model (completion)
|
|
11
|
-
# cached - input tokens served from the provider's prompt cache
|
|
12
|
-
# cache_creation - input tokens written into the prompt cache (Anthropic)
|
|
13
|
-
#
|
|
14
|
-
# All fields are Integer or nil (nil means the provider did not report that
|
|
15
|
-
# value for this call).
|
|
16
|
-
#
|
|
17
|
-
# @example Accumulate usage across a ReAct loop
|
|
18
|
-
# total = Phronomy::TokenUsage.zero
|
|
19
|
-
# chat.messages.each do |msg|
|
|
20
|
-
# total += Phronomy::TokenUsage.from_tokens(msg.tokens)
|
|
21
|
-
# end
|
|
22
|
-
class TokenUsage
|
|
23
|
-
attr_reader :input, :output, :cached, :cache_creation
|
|
24
|
-
|
|
25
|
-
def initialize(input: nil, output: nil, cached: nil, cache_creation: nil)
|
|
26
|
-
@input = input
|
|
27
|
-
@output = output
|
|
28
|
-
@cached = cached
|
|
29
|
-
@cache_creation = cache_creation
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Returns a zero-valued TokenUsage suitable as an accumulator seed.
|
|
33
|
-
def self.zero
|
|
34
|
-
new(input: 0, output: 0, cached: 0, cache_creation: 0)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Builds a TokenUsage from a RubyLLM::Tokens object. Returns zero
|
|
38
|
-
# when tokens is nil (provider did not report usage).
|
|
39
|
-
# nil fields within the tokens object are coerced to 0.
|
|
40
|
-
def self.from_tokens(tokens)
|
|
41
|
-
return zero if tokens.nil?
|
|
42
|
-
|
|
43
|
-
new(
|
|
44
|
-
input: tokens.input || 0,
|
|
45
|
-
output: tokens.output || 0,
|
|
46
|
-
cached: tokens.cache_read || 0,
|
|
47
|
-
cache_creation: tokens.cache_write || 0
|
|
48
|
-
)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Adds two TokenUsage instances. nil fields are treated as 0 so that
|
|
52
|
-
# partially-reported usage accumulates correctly.
|
|
53
|
-
# When other is nil, returns self unchanged.
|
|
54
|
-
def +(other)
|
|
55
|
-
return self if other.nil?
|
|
56
|
-
|
|
57
|
-
self.class.new(
|
|
58
|
-
input: _add(input, other.input),
|
|
59
|
-
output: _add(output, other.output),
|
|
60
|
-
cached: _add(cached, other.cached),
|
|
61
|
-
cache_creation: _add(cache_creation, other.cache_creation)
|
|
62
|
-
)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def ==(other)
|
|
66
|
-
other.is_a?(TokenUsage) &&
|
|
67
|
-
input == other.input &&
|
|
68
|
-
output == other.output &&
|
|
69
|
-
cached == other.cached &&
|
|
70
|
-
cache_creation == other.cache_creation
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def to_h
|
|
74
|
-
{input: input, output: output, cached: cached, cache_creation: cache_creation}
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
private
|
|
78
|
-
|
|
79
|
-
def _add(a, b)
|
|
80
|
-
return nil if a.nil? && b.nil?
|
|
81
|
-
|
|
82
|
-
(a || 0) + (b || 0)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module MultiAgent
|
|
5
|
-
module Persistence
|
|
6
|
-
# Read and assemble domain results; the public entry point owns the execution-thread guard.
|
|
7
|
-
# @api private
|
|
8
|
-
class Queries
|
|
9
|
-
def initialize(repositories)
|
|
10
|
-
@repositories = repositories
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def team_execution_result(team_execution_id)
|
|
14
|
-
execution = @repositories.team_executions.load(team_execution_id)
|
|
15
|
-
{
|
|
16
|
-
team_execution_id: execution.team_execution_id, team_id: execution.team_id,
|
|
17
|
-
status: execution.status, phase: execution.phase,
|
|
18
|
-
result_ref: execution.result_ref, error_ref: execution.error_ref,
|
|
19
|
-
result: execution.result_ref && @repositories.contents.fetch_json(execution.result_ref),
|
|
20
|
-
error: execution.error_ref && @repositories.contents.fetch_json(execution.error_ref)
|
|
21
|
-
}.then { |value| Phronomy::Values::Immutable.copy(value) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def list_team_executions(team_id, after: nil, limit: 100)
|
|
25
|
-
@repositories.team_executions.list(team_id, after: after, limit: limit)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
# Domain-owned Team metadata, independent of coordination runtime loading.
|
|
5
|
-
# @api private
|
|
6
|
-
module TeamStorageSchema
|
|
7
|
-
ROOTS = Phronomy::Storage::Resource.new(id: "team.roots", kind: :records,
|
|
8
|
-
guard: {resource: "team.roots", via: :key})
|
|
9
|
-
EXECUTIONS = Phronomy::Storage::Resource.new(id: "team.executions", kind: :records,
|
|
10
|
-
attributes: {owner: :string, active: :boolean}, immutable_attributes: [:owner],
|
|
11
|
-
indexes: {owner: [:owner], owner_active: [:owner, :active]},
|
|
12
|
-
unique: [{name: :one_active_owner, fields: [:owner], where: {active: true}}],
|
|
13
|
-
guard: {resource: ROOTS.id, via: :owner})
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
class Persistence
|
|
5
|
-
# Content-addressed immutable content repository. ContentStore has its own
|
|
6
|
-
# codec/canonicalization boundary and is not wrapped in DurableRecord.
|
|
7
|
-
#
|
|
8
|
-
# @return [Object]
|
|
9
|
-
# @api public
|
|
10
|
-
def contents = @repositories.contents
|
|
11
|
-
|
|
12
|
-
# Runtime/domain-facing AgentRoot repository. The injected backend is
|
|
13
|
-
# record-oriented; this facade owns encode/decode.
|
|
14
|
-
#
|
|
15
|
-
# @return [Object]
|
|
16
|
-
# @api public
|
|
17
|
-
def agents = @repositories.agents
|
|
18
|
-
|
|
19
|
-
# Runtime/domain-facing append-only Agent Journal repository.
|
|
20
|
-
#
|
|
21
|
-
# @return [Object]
|
|
22
|
-
# @api public
|
|
23
|
-
def journals = @repositories.journals
|
|
24
|
-
|
|
25
|
-
# Runtime/domain-facing AgentExecution repository.
|
|
26
|
-
#
|
|
27
|
-
# @return [Object]
|
|
28
|
-
# @api public
|
|
29
|
-
def executions = @repositories.executions
|
|
30
|
-
|
|
31
|
-
# Runtime/domain-facing durable Workflow snapshot repository.
|
|
32
|
-
#
|
|
33
|
-
# @return [Object]
|
|
34
|
-
# @api public
|
|
35
|
-
def workflow_states = @repositories.workflow_states
|
|
36
|
-
|
|
37
|
-
# Purpose-specific durable Handoff and Team repositories in atomic_all.
|
|
38
|
-
# @api public
|
|
39
|
-
def handoff_states = @repositories.handoff_states
|
|
40
|
-
|
|
41
|
-
# @api public
|
|
42
|
-
def teams = @repositories.teams
|
|
43
|
-
|
|
44
|
-
# @api public
|
|
45
|
-
def team_executions = @repositories.team_executions
|
|
46
|
-
|
|
47
|
-
# Read-only exact Agent execution result; never creates a live Agent owner.
|
|
48
|
-
# Result is nil until a result_ref exists; errors remain canonical data.
|
|
49
|
-
# @api public
|
|
50
|
-
def execution_result(execution_id)
|
|
51
|
-
assert_observation_thread!
|
|
52
|
-
Phronomy::Agent::Persistence::Queries.new(self).execution_result(execution_id)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Follows one exact Handoff turn without constructing a live Agent or graph.
|
|
56
|
-
# A committed absent Target reservation remains active; failed reads raise.
|
|
57
|
-
# @api public
|
|
58
|
-
def handoff_result(execution_id, main_agent_id: nil)
|
|
59
|
-
assert_observation_thread!
|
|
60
|
-
Phronomy::Agent::Persistence::Queries.new(self).handoff_result(execution_id, main_agent_id: main_agent_id)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Lists retained active and terminal executions in lexical ID order.
|
|
64
|
-
# after is an exclusive ID cursor; discovery does not imply request dedup.
|
|
65
|
-
# @api public
|
|
66
|
-
def list_executions(agent_id, after: nil, limit: 100)
|
|
67
|
-
assert_observation_thread!
|
|
68
|
-
Phronomy::Agent::Persistence::Queries.new(self).list_executions(agent_id, after: after, limit: limit)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Read-only exact Team result, independent of current Team class/Proc wiring.
|
|
72
|
-
# @api public
|
|
73
|
-
def team_execution_result(team_execution_id)
|
|
74
|
-
assert_observation_thread!
|
|
75
|
-
Phronomy::MultiAgent::Persistence::Queries.new(self).team_execution_result(team_execution_id)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Lists retained Team runs; no continuation or callback delivery occurs.
|
|
79
|
-
# @api public
|
|
80
|
-
def list_team_executions(team_id, after: nil, limit: 100)
|
|
81
|
-
assert_observation_thread!
|
|
82
|
-
Phronomy::MultiAgent::Persistence::Queries.new(self).list_team_executions(team_id, after: after, limit: limit)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# The selected raw storage backend, for backend-specific administration.
|
|
86
|
-
# Read and write domain records through the repository accessors above.
|
|
87
|
-
# @api public
|
|
88
|
-
attr_reader :backend
|
|
89
|
-
|
|
90
|
-
# Assembles domain repositories over one synchronous storage backend.
|
|
91
|
-
# @api public
|
|
92
|
-
def initialize(backend:)
|
|
93
|
-
Phronomy::Storage::Backend.validate_capabilities!(backend)
|
|
94
|
-
PersistenceComposition::StorageSchema.validate!(backend.view)
|
|
95
|
-
@backend = backend
|
|
96
|
-
@repositories = PersistenceComposition::Repositories.new(backend.view)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Constructs an isolated in-memory storage domain with standard codecs.
|
|
100
|
-
# @api public
|
|
101
|
-
def self.in_memory
|
|
102
|
-
new(backend: Phronomy::Storage::Backends::InMemory.new(resources: PersistenceComposition::StorageSchema.resources))
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# @api public
|
|
106
|
-
def capabilities = {atomic_all: true, atomic_admission: true, optimistic_revision: true}.freeze
|
|
107
|
-
|
|
108
|
-
# Executes a single backend transaction and exposes domain repositories
|
|
109
|
-
# bound to its raw view. Codec and caller failures remain inside the backend
|
|
110
|
-
# block so the backend can roll them back. The block result is returned.
|
|
111
|
-
# Explicit nested calls on this service use savepoint semantics: a failed
|
|
112
|
-
# inner scope rolls back and re-raises; a successful inner scope is committed
|
|
113
|
-
# only with its outer scope. See Storage::Backend#transaction.
|
|
114
|
-
# Storage failures whose commit outcome is fundamentally
|
|
115
|
-
# unknown remain backend/database failures; Phronomy does not claim
|
|
116
|
-
# exactly-once semantics for such failures.
|
|
117
|
-
# @api public
|
|
118
|
-
def transaction
|
|
119
|
-
backend.transaction do |raw_view|
|
|
120
|
-
repositories = PersistenceComposition::Repositories.new(raw_view)
|
|
121
|
-
yield repositories
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# @api public
|
|
126
|
-
def assert_agent_watermark!(agent_id:, agent_revision:, journal_position:)
|
|
127
|
-
@repositories.assert_agent_watermark!(
|
|
128
|
-
agent_id: agent_id, agent_revision: agent_revision, journal_position: journal_position
|
|
129
|
-
)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
private
|
|
133
|
-
|
|
134
|
-
def assert_observation_thread!
|
|
135
|
-
if Phronomy::Runtime.in_event_loop_context?
|
|
136
|
-
raise Phronomy::EventLoopReentrancyError, "Persistence observation cannot block EventLoop"
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
module PersistenceComposition
|
|
5
|
-
# Assemble domain repositories over one raw backend or transaction view.
|
|
6
|
-
# @api private
|
|
7
|
-
class Repositories
|
|
8
|
-
attr_reader :contents
|
|
9
|
-
|
|
10
|
-
def initialize(view)
|
|
11
|
-
@view = view
|
|
12
|
-
@contents = Phronomy::ContentStore::StoredContents.new(view)
|
|
13
|
-
@domain_repositories = {}
|
|
14
|
-
@repository_lock = Mutex.new
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def agents
|
|
18
|
-
domain_repository(:agents) do
|
|
19
|
-
Phronomy::Agent::Persistence::AgentRepository.new(@view)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def journals
|
|
24
|
-
domain_repository(:journals) do
|
|
25
|
-
Phronomy::Agent::Persistence::JournalRepository.new(@view)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def executions
|
|
30
|
-
domain_repository(:executions) do
|
|
31
|
-
Phronomy::Agent::Persistence::ExecutionRepository.new(@view)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def workflow_states
|
|
36
|
-
domain_repository(:workflow_states) do
|
|
37
|
-
Phronomy::Workflow::Persistence::StateRepository.new(@view)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def handoff_states
|
|
42
|
-
domain_repository(:handoff_states) do
|
|
43
|
-
Phronomy::Agent::Persistence::HandoffStateRepository.new(@view)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def teams
|
|
48
|
-
domain_repository(:teams) do
|
|
49
|
-
Phronomy::MultiAgent::Persistence::TeamRepository.new(@view)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def team_executions
|
|
54
|
-
domain_repository(:team_executions) do
|
|
55
|
-
Phronomy::MultiAgent::Persistence::TeamExecutionRepository.new(@view)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def assert_agent_watermark!(agent_id:, agent_revision:, journal_position:)
|
|
60
|
-
Phronomy::Agent::Persistence::Watermark.new(@view).check!(
|
|
61
|
-
agent_id: agent_id.to_s,
|
|
62
|
-
agent_revision: Integer(agent_revision),
|
|
63
|
-
journal_position: Integer(journal_position)
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
# Cache one wrapper per view without loading unused domain implementations.
|
|
70
|
-
def domain_repository(name)
|
|
71
|
-
@repository_lock.synchronize do
|
|
72
|
-
@domain_repositories.fetch(name) { @domain_repositories[name] = yield }
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|