phronomy 0.26.0 → 0.27.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/CHANGELOG.md +40 -0
- data/README.md +4 -0
- data/VERIFY.sh +27 -27
- data/benchmark/bench_agent_invoke.rb +26 -22
- data/benchmark/bench_context_assembler.rb +4 -5
- data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
- data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
- data/docs/architecture/agent-context.md +4 -2
- data/docs/architecture/agent-transition-ownership.md +89 -0
- data/docs/architecture/before-llm-input.md +6 -0
- data/docs/architecture/context-management.md +30 -0
- data/docs/architecture/context-preparation-steps.md +90 -0
- data/docs/architecture/entry-action-and-team-wording.md +72 -0
- data/docs/architecture/execution-metadata-and-values.md +80 -0
- data/docs/architecture/generator-verifier-ownership.md +111 -0
- data/docs/architecture/multi-agent-handoff.md +8 -2
- data/docs/architecture/persistence-refactoring-plan.md +50 -0
- data/docs/architecture/persistence.md +27 -4
- data/docs/architecture/refactoring-closure.md +334 -0
- data/docs/architecture/remaining-refactoring-plan.md +374 -0
- data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
- data/docs/architecture/tool-schema-recording-gap.md +50 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
- data/docs/architecture.md +209 -0
- data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
- data/docs/decisions/032-storage-backend-composition.md +80 -0
- data/docs/decisions/033-domain-persistence-ownership.md +79 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
- data/docs/decisions/036-context-contract-ownership.md +86 -0
- data/docs/decisions/037-common-definition-ownership.md +62 -0
- data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
- data/docs/decisions/040-configuration-default-composition.md +94 -0
- data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
- data/docs/decisions/042-feature-owned-execution-state.md +106 -0
- data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
- data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
- data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
- data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
- data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
- data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
- data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
- data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
- data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
- data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
- data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
- data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
- data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
- data/docs/decisions/058-neutral-storage-primitives.md +78 -0
- data/docs/decisions/README.md +35 -6
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
- data/docs/features.md +9 -3
- data/docs/getting-started.md +4 -4
- data/docs/migrations/0.15.md +5 -0
- data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
- data/docs/migrations/handoff-runner-multi-agent.md +35 -0
- data/docs/migrations/neutral-storage-spi.md +43 -0
- data/docs/migrations/parallel-tool-chat-removal.md +49 -0
- data/docs/migrations/shared-state-multi-agent.md +44 -0
- data/docs/migrations/storage-backend-composition.md +117 -0
- data/docs/migrations/storage-transaction-boundaries.md +74 -0
- data/docs/persistence-backends.md +162 -204
- data/docs/runtime-and-concurrency.md +117 -32
- data/lib/phronomy/agent/api/agent.rb +17 -0
- data/lib/phronomy/agent/async_event_api.rb +2 -2
- data/lib/phronomy/agent/base.rb +51 -241
- data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
- data/lib/phronomy/agent/context/capability/base.rb +67 -26
- data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
- data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
- data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
- data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
- data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
- data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
- data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
- data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
- data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
- data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
- data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
- data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
- data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
- data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
- data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
- data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
- data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
- data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
- data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
- data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
- data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
- data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
- data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
- data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
- data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
- data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
- data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
- data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
- data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
- data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
- data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
- data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
- data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
- data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
- data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
- data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
- data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
- data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
- data/lib/phronomy/agent/persistence/codec.rb +358 -0
- data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
- data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
- data/lib/phronomy/agent/persistence/queries.rb +61 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
- data/lib/phronomy/agent/persistence/watermark.rb +27 -0
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
- data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
- data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
- data/lib/phronomy/agent/selection/candidate.rb +1 -1
- data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
- data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
- data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
- data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
- data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
- data/lib/phronomy/common/configuration_error.rb +7 -0
- data/lib/phronomy/common/error.rb +5 -0
- data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
- data/lib/phronomy/common/values/serializable.rb +32 -0
- data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
- data/lib/phronomy/configuration/global_configuration.rb +26 -0
- data/lib/phronomy/content_store/storage_schema.rb +11 -0
- data/lib/phronomy/content_store/stored_contents.rb +43 -0
- data/lib/phronomy/engine/backpressure_error.rb +7 -0
- data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
- data/lib/phronomy/engine/cancellation_error.rb +7 -0
- data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
- data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
- data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
- data/lib/phronomy/engine/event_loop.rb +158 -624
- data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
- data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
- data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
- data/lib/phronomy/engine/execution_receiver.rb +65 -0
- data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
- data/lib/phronomy/engine/fsm_protocol.rb +14 -0
- data/lib/phronomy/engine/fsm_session.rb +35 -28
- data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
- data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
- data/lib/phronomy/engine/runtime.rb +80 -84
- data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
- data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
- data/lib/phronomy/engine/task_result.rb +4 -0
- data/lib/phronomy/engine/timeout_error.rb +7 -0
- data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
- data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
- data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
- data/lib/phronomy/generation/generator_verifier.rb +118 -0
- data/lib/phronomy/generation/low_confidence_error.rb +14 -0
- data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
- data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
- data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
- data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
- data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
- data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
- data/lib/phronomy/llm_contract/transport_error.rb +7 -0
- data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
- data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
- data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
- data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
- data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
- data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
- data/lib/phronomy/multi_agent/team_execution.rb +1 -1
- data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
- data/lib/phronomy/multi_agent/team_root.rb +1 -1
- data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
- data/lib/phronomy/persistence/api/persistence.rb +140 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
- data/lib/phronomy/persistence_composition/repositories.rb +77 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
- data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
- data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
- data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
- data/lib/phronomy/storage/backend.rb +101 -0
- data/lib/phronomy/storage/backends/in_memory.rb +157 -0
- data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
- data/lib/phronomy/storage/blobs.rb +31 -0
- data/lib/phronomy/storage/condition.rb +25 -0
- data/lib/phronomy/storage/condition_failed_error.rb +16 -0
- data/lib/phronomy/storage/conflict_error.rb +9 -0
- data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
- data/lib/phronomy/storage/entry.rb +33 -0
- data/lib/phronomy/storage/guard_ref.rb +13 -0
- data/lib/phronomy/storage/not_found_error.rb +9 -0
- data/lib/phronomy/storage/record_codec.rb +177 -0
- data/lib/phronomy/storage/records.rb +61 -0
- data/lib/phronomy/storage/resource.rb +126 -0
- data/lib/phronomy/storage/scope.rb +25 -0
- data/lib/phronomy/storage/serialization_error.rb +9 -0
- data/lib/phronomy/storage/streams.rb +44 -0
- data/lib/phronomy/storage/transaction_error.rb +10 -0
- data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
- data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
- data/lib/phronomy/storage/validation.rb +53 -0
- data/lib/phronomy/storage/view.rb +131 -0
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
- data/lib/phronomy/testing/persistence_contract.rb +4 -0
- data/lib/phronomy/tool/contract/tool_error.rb +7 -0
- data/lib/phronomy/tools/agent.rb +1 -1
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
- data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
- data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
- data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
- data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
- data/lib/phronomy/workflow/persistence/codec.rb +153 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
- data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
- data/lib/phronomy.rb +52 -94
- data/scripts/api_snapshot.rb +1 -1
- data/scripts/storage_spi_snapshot.rb +36 -0
- data/sig/phronomy/agent.rbs +0 -1
- data/sig/phronomy/execution_receiver.rbs +34 -0
- data/sig/phronomy/handoff.rbs +4 -2
- data/sig/phronomy/multi_agent.rbs +18 -0
- data/sig/phronomy/persistence.rbs +7 -91
- data/sig/phronomy/storage.rbs +174 -0
- data/sig/phronomy/tool.rbs +10 -1
- metadata +230 -99
- data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
- data/lib/phronomy/agent/recovery_support.rb +0 -504
- data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
- data/lib/phronomy/agent/tool_executor.rb +0 -55
- data/lib/phronomy/generator_verifier.rb +0 -369
- data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
- data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
- data/lib/phronomy/persistence/durable_codec.rb +0 -706
- data/lib/phronomy/persistence/in_memory.rb +0 -690
- data/lib/phronomy/persistence/repository_facades.rb +0 -535
- data/lib/phronomy/persistence.rb +0 -276
- data/lib/phronomy/ruby_llm_patches.rb +0 -24
- data/lib/phronomy/workflow_recovery.rb +0 -123
- /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
- /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
- /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
- /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
- /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
- /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
- /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
- /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
- /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
- /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
- /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
class Workflow
|
|
5
|
+
module Persistence
|
|
6
|
+
# Current-format record schemas and conversion for this domain.
|
|
7
|
+
# @api private
|
|
8
|
+
module Codec
|
|
9
|
+
extend Phronomy::Storage::RecordCodec
|
|
10
|
+
|
|
11
|
+
WORKFLOW_STATE_RECORD_TYPE = "phronomy.workflow_state"
|
|
12
|
+
WORKFLOW_STATE_FORMAT_VERSION = "0.1"
|
|
13
|
+
WORKFLOW_STATE_KEYS = %w[
|
|
14
|
+
workflow_instance_id workflow_revision snapshot
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
WORKFLOW_SNAPSHOT_KEYS = %w[fields phase].freeze
|
|
18
|
+
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
def encode_workflow_state(workflow_instance_id:, workflow_revision:, snapshot:)
|
|
22
|
+
normalized_snapshot = canonicalize_workflow_snapshot(snapshot)
|
|
23
|
+
validate_workflow_snapshot!(normalized_snapshot)
|
|
24
|
+
revision = Integer(workflow_revision)
|
|
25
|
+
unless revision.positive?
|
|
26
|
+
raise Phronomy::Storage::SerializationError,
|
|
27
|
+
"Workflow durable revision must be positive"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
payload = {
|
|
31
|
+
"workflow_instance_id" => String(workflow_instance_id),
|
|
32
|
+
"workflow_revision" => revision,
|
|
33
|
+
"snapshot" => normalized_snapshot
|
|
34
|
+
}
|
|
35
|
+
validate_workflow_state_payload!(payload)
|
|
36
|
+
build_record(WORKFLOW_STATE_RECORD_TYPE, WORKFLOW_STATE_FORMAT_VERSION, payload)
|
|
37
|
+
rescue Phronomy::Storage::SerializationError
|
|
38
|
+
raise
|
|
39
|
+
rescue => error
|
|
40
|
+
serialization_error("cannot encode Workflow state", error)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def decode_workflow_state(record, expected_workflow_instance_id: nil)
|
|
44
|
+
payload = current_payload!(
|
|
45
|
+
record,
|
|
46
|
+
record_type: WORKFLOW_STATE_RECORD_TYPE,
|
|
47
|
+
format_version: WORKFLOW_STATE_FORMAT_VERSION,
|
|
48
|
+
keys: WORKFLOW_STATE_KEYS,
|
|
49
|
+
label: "Workflow state payload"
|
|
50
|
+
)
|
|
51
|
+
validate_workflow_state_payload!(payload)
|
|
52
|
+
workflow_instance_id = payload.fetch("workflow_instance_id")
|
|
53
|
+
if expected_workflow_instance_id &&
|
|
54
|
+
workflow_instance_id != expected_workflow_instance_id.to_s
|
|
55
|
+
raise Phronomy::Storage::SerializationError,
|
|
56
|
+
"Workflow state identity mismatch: #{workflow_instance_id.inspect} != " \
|
|
57
|
+
"#{expected_workflow_instance_id.to_s.inspect}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
snapshot: immutable_copy(payload.fetch("snapshot")),
|
|
62
|
+
revision: payload.fetch("workflow_revision")
|
|
63
|
+
}.freeze
|
|
64
|
+
rescue Phronomy::Storage::SerializationError
|
|
65
|
+
raise
|
|
66
|
+
rescue => error
|
|
67
|
+
serialization_error("cannot decode Workflow state", error)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def validate_workflow_state_payload!(payload)
|
|
71
|
+
validate_exact_keys!(payload, WORKFLOW_STATE_KEYS, label: "Workflow state payload")
|
|
72
|
+
require_nonempty_string!(payload, "workflow_instance_id", label: "Workflow state payload")
|
|
73
|
+
require_positive_integer!(payload, "workflow_revision", label: "Workflow state payload")
|
|
74
|
+
validate_workflow_snapshot!(payload.fetch("snapshot"))
|
|
75
|
+
payload
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def validate_workflow_snapshot!(snapshot)
|
|
79
|
+
validate_exact_keys!(snapshot, WORKFLOW_SNAPSHOT_KEYS, label: "Workflow snapshot")
|
|
80
|
+
unless snapshot.fetch("fields").is_a?(Hash)
|
|
81
|
+
raise Phronomy::Storage::SerializationError,
|
|
82
|
+
"Workflow snapshot fields must be a Hash"
|
|
83
|
+
end
|
|
84
|
+
phase = snapshot.fetch("phase")
|
|
85
|
+
unless phase.nil? || phase.is_a?(String)
|
|
86
|
+
raise Phronomy::Storage::SerializationError,
|
|
87
|
+
"Workflow snapshot phase must be a String or nil"
|
|
88
|
+
end
|
|
89
|
+
Phronomy::CanonicalJSON.dump(snapshot)
|
|
90
|
+
snapshot
|
|
91
|
+
rescue ArgumentError => error
|
|
92
|
+
raise Phronomy::Storage::SerializationError,
|
|
93
|
+
"Workflow snapshot is not canonical JSON compatible: #{error.message}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def canonicalize_workflow_snapshot(snapshot)
|
|
97
|
+
source = top_level_string_keys(snapshot, label: "Workflow snapshot")
|
|
98
|
+
fields = source.fetch("fields")
|
|
99
|
+
unless fields.is_a?(Hash)
|
|
100
|
+
raise Phronomy::Storage::SerializationError,
|
|
101
|
+
"Workflow snapshot fields must be a Hash"
|
|
102
|
+
end
|
|
103
|
+
{
|
|
104
|
+
"fields" => canonicalize_workflow_value(fields),
|
|
105
|
+
"phase" => source["phase"]&.to_s
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def canonicalize_workflow_value(value)
|
|
110
|
+
case value
|
|
111
|
+
when Hash
|
|
112
|
+
value.each_with_object({}) do |(key, child), result|
|
|
113
|
+
unless key.is_a?(String) || key.is_a?(Symbol)
|
|
114
|
+
raise Phronomy::Storage::SerializationError,
|
|
115
|
+
"Workflow field key must be String or Symbol, got #{key.class}"
|
|
116
|
+
end
|
|
117
|
+
string_key = key.to_s
|
|
118
|
+
if result.key?(string_key)
|
|
119
|
+
raise Phronomy::Storage::SerializationError,
|
|
120
|
+
"duplicate Workflow field key after normalization: #{string_key.inspect}"
|
|
121
|
+
end
|
|
122
|
+
result[string_key] = canonicalize_workflow_value(child)
|
|
123
|
+
end
|
|
124
|
+
when Array
|
|
125
|
+
value.map { |child| canonicalize_workflow_value(child) }
|
|
126
|
+
when Symbol
|
|
127
|
+
value.to_s
|
|
128
|
+
when String, Integer, Float, TrueClass, FalseClass, NilClass
|
|
129
|
+
value
|
|
130
|
+
else
|
|
131
|
+
raise Phronomy::Storage::SerializationError,
|
|
132
|
+
"unsupported Workflow durable value: #{value.class}"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def immutable_copy(value)
|
|
137
|
+
case value
|
|
138
|
+
when Hash
|
|
139
|
+
value.each_with_object({}) do |(key, child), result|
|
|
140
|
+
result[key.dup.freeze] = immutable_copy(child)
|
|
141
|
+
end.freeze
|
|
142
|
+
when Array
|
|
143
|
+
value.map { |child| immutable_copy(child) }.freeze
|
|
144
|
+
when String
|
|
145
|
+
value.dup.freeze
|
|
146
|
+
else
|
|
147
|
+
value
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
class Workflow
|
|
5
|
+
module Persistence
|
|
6
|
+
# Owns Workflow snapshot encoding and the initial revision.
|
|
7
|
+
# @api private
|
|
8
|
+
class StateRepository
|
|
9
|
+
def initialize(view) = @view = view
|
|
10
|
+
|
|
11
|
+
def load(workflow_instance_id)
|
|
12
|
+
@view.atomic do |bound|
|
|
13
|
+
entry = bound.records(Phronomy::WorkflowStorageSchema::STATES).read(workflow_instance_id.to_s)
|
|
14
|
+
entry && decode(entry, workflow_instance_id)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def save(workflow_instance_id, expected_revision:, snapshot:)
|
|
19
|
+
expected = expected_revision.nil? ? nil : Integer(expected_revision)
|
|
20
|
+
revision = expected.nil? ? 1 : expected + 1
|
|
21
|
+
record = Codec.encode_workflow_state(workflow_instance_id: workflow_instance_id,
|
|
22
|
+
workflow_revision: revision, snapshot: snapshot)
|
|
23
|
+
@view.atomic do |bound|
|
|
24
|
+
records = bound.records(Phronomy::WorkflowStorageSchema::STATES)
|
|
25
|
+
values = {key: workflow_instance_id.to_s, attributes: {}, record: record}
|
|
26
|
+
entry = if expected.nil?
|
|
27
|
+
records.insert(**values, revision: revision)
|
|
28
|
+
else
|
|
29
|
+
records.replace(**values, expected_revision: expected, next_revision: revision)
|
|
30
|
+
end
|
|
31
|
+
decoded = decode(entry, workflow_instance_id)
|
|
32
|
+
unless decoded.fetch(:revision) == revision
|
|
33
|
+
raise Phronomy::Storage::SerializationError, "backend returned another Workflow revision"
|
|
34
|
+
end
|
|
35
|
+
revision
|
|
36
|
+
end
|
|
37
|
+
rescue Phronomy::Storage::NotFoundError => error
|
|
38
|
+
raise Phronomy::Storage::ConflictError, error.message
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def delete(workflow_instance_id, expected_revision:)
|
|
42
|
+
@view.records(Phronomy::WorkflowStorageSchema::STATES).delete(key: workflow_instance_id.to_s, expected_revision: Integer(expected_revision))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def decode(entry, workflow_instance_id)
|
|
48
|
+
decoded = Codec.decode_workflow_state(entry.record, expected_workflow_instance_id: workflow_instance_id)
|
|
49
|
+
unless entry.key == workflow_instance_id.to_s && decoded.fetch(:revision) == entry.revision
|
|
50
|
+
raise Phronomy::Storage::SerializationError, "backend returned another Workflow identity/revision"
|
|
51
|
+
end
|
|
52
|
+
decoded
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -32,7 +32,7 @@ module Phronomy
|
|
|
32
32
|
|
|
33
33
|
def build
|
|
34
34
|
entry = @entry_point
|
|
35
|
-
all_states = (@declared_states + @wait_state_names + [
|
|
35
|
+
all_states = (@declared_states + @wait_state_names + [FSMProtocol::FINISH]).uniq
|
|
36
36
|
auto_transitions = @auto_transitions
|
|
37
37
|
external_events = @external_events
|
|
38
38
|
entry_actions = @entry_actions
|
|
@@ -188,7 +188,7 @@ module Phronomy
|
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
def public_destination(destination)
|
|
191
|
-
return :__finish__ if destination ==
|
|
191
|
+
return :__finish__ if destination == FSMProtocol::FINISH
|
|
192
192
|
|
|
193
193
|
destination
|
|
194
194
|
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Phronomy
|
|
4
|
+
# Domain-owned Workflow metadata, loadable without the Workflow runtime.
|
|
5
|
+
# @api private
|
|
6
|
+
module WorkflowStorageSchema
|
|
7
|
+
STATES = Phronomy::Storage::Resource.new(id: "workflow.states", kind: :records)
|
|
8
|
+
end
|
|
9
|
+
end
|
data/lib/phronomy.rb
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require "zeitwerk"
|
|
4
4
|
require "ruby_llm"
|
|
5
|
-
require_relative "phronomy/
|
|
5
|
+
require_relative "phronomy/version"
|
|
6
6
|
|
|
7
7
|
loader = Zeitwerk::Loader.for_gem
|
|
8
8
|
loader.inflector.inflect("ruby_llm_embeddings" => "RubyLLMEmbeddings")
|
|
9
9
|
loader.inflector.inflect("rag" => "RAG")
|
|
10
10
|
loader.inflector.inflect("fsm_session" => "FSMSession")
|
|
11
|
+
loader.inflector.inflect("fsm_protocol" => "FSMProtocol")
|
|
11
12
|
loader.inflector.inflect("llm_adapter" => "LLMAdapter")
|
|
12
13
|
loader.inflector.inflect("llm_operation_result" => "LLMOperationResult")
|
|
13
14
|
loader.inflector.inflect("ruby_llm" => "RubyLLM")
|
|
@@ -18,104 +19,61 @@ loader.inflector.inflect("llm_input_manifest" => "LLMInputManifest")
|
|
|
18
19
|
loader.inflector.inflect("llm_input_build_context" => "LLMInputBuildContext")
|
|
19
20
|
loader.inflector.inflect("llm_input_patch" => "LLMInputPatch")
|
|
20
21
|
loader.inflector.inflect("before_llm_input" => "BeforeLLMInput")
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
loader.
|
|
24
|
-
|
|
25
|
-
#
|
|
22
|
+
# These responsibility directories do not add a public Ruby namespace.
|
|
23
|
+
%w[common configuration engine generation llm_contract recovery].each do |directory|
|
|
24
|
+
loader.collapse("#{__dir__}/phronomy/#{directory}")
|
|
25
|
+
end
|
|
26
|
+
# Agent responsibility directories retain the existing Agent constant names.
|
|
27
|
+
%w[
|
|
28
|
+
context_contract lifecycle execution tool_execution context_assembly
|
|
29
|
+
journal handoff recovery
|
|
30
|
+
].each do |directory|
|
|
31
|
+
loader.collapse("#{__dir__}/phronomy/agent/#{directory}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# A nested root is independent of its enclosing Ruby namespace. Keep existing
|
|
35
|
+
# Phronomy::Workflow, Phronomy::WorkflowContext, and other canonical constants
|
|
36
|
+
# beside the feature they belong to, without aliases or a new partial-load API.
|
|
37
|
+
%w[
|
|
38
|
+
agent/api
|
|
39
|
+
agent/lifecycle_contract
|
|
40
|
+
filter/contract
|
|
41
|
+
output_parser/contract
|
|
42
|
+
persistence/api
|
|
43
|
+
tool/contract
|
|
44
|
+
workflow/execution
|
|
45
|
+
workflow/storage_contract
|
|
46
|
+
multi_agent/storage_contract
|
|
47
|
+
].each do |directory|
|
|
48
|
+
loader.push_dir("#{__dir__}/phronomy/#{directory}", namespace: Phronomy)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# These files wire composition, reopen namespaces, or patch a dependency.
|
|
52
|
+
loader.ignore(
|
|
53
|
+
"#{__dir__}/phronomy/configuration/global_configuration.rb",
|
|
54
|
+
"#{__dir__}/phronomy/agent/composition",
|
|
55
|
+
"#{__dir__}/phronomy/runtime_composition/agent_defaults.rb",
|
|
56
|
+
"#{__dir__}/phronomy/runtime_composition/configuration_defaults.rb",
|
|
57
|
+
"#{__dir__}/phronomy/runtime_composition/global_runtime.rb"
|
|
58
|
+
)
|
|
59
|
+
# Persistence conformance support must never make production loading require RSpec.
|
|
26
60
|
loader.ignore(
|
|
27
61
|
"#{__dir__}/phronomy/testing/persistence_contract.rb",
|
|
28
62
|
"#{__dir__}/phronomy/testing/persistence_contract"
|
|
29
63
|
)
|
|
30
64
|
loader.setup
|
|
31
65
|
|
|
32
|
-
require_relative "phronomy/
|
|
33
|
-
require_relative "phronomy/token_usage"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class Error < StandardError; end
|
|
37
|
-
class ParseError < Error; end
|
|
38
|
-
class RecursionLimitError < Error; end
|
|
39
|
-
class ToolError < Error; end
|
|
40
|
-
class TimeoutError < Error; end
|
|
41
|
-
class ConfigurationError < Error; end
|
|
42
|
-
class HandoffError < Error; end
|
|
43
|
-
|
|
44
|
-
class TransportError < Error; end
|
|
45
|
-
class RateLimitError < TransportError; end
|
|
46
|
-
class AuthenticationError < TransportError; end
|
|
47
|
-
class ContextLengthError < Error; end
|
|
48
|
-
class CancellationError < Error; end
|
|
49
|
-
|
|
50
|
-
# Raised when a synchronous API would block the EventLoop control thread.
|
|
51
|
-
class EventLoopReentrancyError < Error; end
|
|
52
|
-
|
|
53
|
-
# Backward-compatible error class name for callers that still rescue the old
|
|
54
|
-
# scheduler-oriented exception. New code should use EventLoopReentrancyError.
|
|
55
|
-
class SchedulerReentrancyError < EventLoopReentrancyError; end
|
|
66
|
+
require_relative "phronomy/runtime_composition/configuration_defaults"
|
|
67
|
+
require_relative "phronomy/llm_contract/token_usage"
|
|
68
|
+
require_relative "phronomy/configuration/global_configuration"
|
|
69
|
+
require_relative "phronomy/runtime_composition/global_runtime"
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def initialize(result)
|
|
64
|
-
@result = result
|
|
65
|
-
super("Answer confidence #{result.confidence} is below the required threshold")
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
class FilterBlockError < Error
|
|
70
|
-
attr_reader :filter
|
|
71
|
-
|
|
72
|
-
def initialize(message, filter: nil)
|
|
73
|
-
super(message)
|
|
74
|
-
@filter = filter
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class PoolShutdownError < Error; end
|
|
79
|
-
class BackpressureError < Error; end
|
|
80
|
-
|
|
81
|
-
class WorkflowContextOwnershipError < Error; end
|
|
82
|
-
|
|
83
|
-
class << self
|
|
84
|
-
def configuration
|
|
85
|
-
@configuration ||= Configuration.new
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def configure
|
|
89
|
-
yield configuration
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def reset_configuration!
|
|
93
|
-
@configuration = Configuration.new
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def with_configuration
|
|
97
|
-
original = @configuration&.dup
|
|
98
|
-
yield configuration
|
|
99
|
-
ensure
|
|
100
|
-
@configuration = original
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def reset_runtime!(timeout: configuration.event_loop_stop_grace_seconds)
|
|
104
|
-
previous_grace = @configuration&.event_loop_stop_grace_seconds
|
|
105
|
-
result = Runtime.reset_default!(timeout: timeout)
|
|
106
|
-
|
|
107
|
-
new_configuration = Configuration.new
|
|
108
|
-
if previous_grace
|
|
109
|
-
new_configuration.event_loop_stop_grace_seconds = previous_grace
|
|
110
|
-
end
|
|
111
|
-
@configuration = new_configuration
|
|
112
|
-
result
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
71
|
+
# Explicitly install the Agent namespace extensions even if its factory
|
|
72
|
+
# contract was loaded first. Composition owns both concrete binding and the
|
|
73
|
+
# run_once method definition; neither is required from Agent execution files.
|
|
74
|
+
require_relative "phronomy/agent/api/agent"
|
|
75
|
+
require_relative "phronomy/runtime_composition/agent_defaults"
|
|
76
|
+
require_relative "phronomy/agent/composition/run_once"
|
|
116
77
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
# Agent namespace is materialized.
|
|
120
|
-
require_relative "phronomy/recovery"
|
|
121
|
-
require_relative "phronomy/workflow_recovery"
|
|
78
|
+
# Load the common recovery vocabulary during ordinary application loading.
|
|
79
|
+
require_relative "phronomy/recovery/recovery"
|
data/scripts/api_snapshot.rb
CHANGED
|
@@ -36,7 +36,7 @@ PUBLIC_API_ENTRIES = [
|
|
|
36
36
|
# Beta
|
|
37
37
|
Phronomy::Agent::Handoff,
|
|
38
38
|
Phronomy::Agent::HandoffPolicy,
|
|
39
|
-
Phronomy::
|
|
39
|
+
Phronomy::MultiAgent::HandoffRunner,
|
|
40
40
|
Phronomy::MultiAgent::Orchestrator,
|
|
41
41
|
Phronomy::MultiAgent::TeamCoordinator,
|
|
42
42
|
Phronomy::Filter::Base,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "../lib/phronomy"
|
|
6
|
+
|
|
7
|
+
# Explicit SPI 2 scope, independent of the Stable/Beta product API snapshot.
|
|
8
|
+
# Private dispatch and domain composition helpers are deliberately excluded.
|
|
9
|
+
surfaces = {
|
|
10
|
+
Phronomy::Persistence => Phronomy::Persistence.public_instance_methods(false).sort,
|
|
11
|
+
Phronomy::Storage::Backend => %i[initialize capabilities transaction resources view],
|
|
12
|
+
Phronomy::Storage::Backends::InMemory => %i[initialize capabilities],
|
|
13
|
+
Phronomy::Storage::View => %i[records streams blobs check!],
|
|
14
|
+
Phronomy::Storage::Resource => %i[initialize id kind attributes immutable_attributes indexes unique guard validate_attributes index_values],
|
|
15
|
+
Phronomy::Storage::Records => %i[resource insert read fetch replace delete scan delete_matching],
|
|
16
|
+
Phronomy::Storage::Streams => %i[resource append read head delete],
|
|
17
|
+
Phronomy::Storage::Blobs => %i[resource put_if_absent fetch exist?],
|
|
18
|
+
Phronomy::Storage::GuardRef => %i[initialize resource key],
|
|
19
|
+
Phronomy::Storage::Condition::RevisionIs => %i[initialize resource key expected],
|
|
20
|
+
Phronomy::Storage::Condition::StreamHeadIs => %i[initialize resource stream expected],
|
|
21
|
+
Phronomy::Storage::Condition::NoRows => %i[initialize resource index equals],
|
|
22
|
+
Phronomy::Storage::Entry::Record => %i[initialize key revision attributes record],
|
|
23
|
+
Phronomy::Storage::Entry::Stream => %i[initialize position id record],
|
|
24
|
+
Phronomy::Storage::Entry::Append => %i[initialize id record],
|
|
25
|
+
Phronomy::Storage::Entry::Blob => %i[initialize key bytes attributes],
|
|
26
|
+
Phronomy::Storage::UniqueConstraintError => %i[initialize resource constraint],
|
|
27
|
+
Phronomy::Storage::ConditionFailedError => %i[initialize condition]
|
|
28
|
+
}
|
|
29
|
+
snapshot = {spi_version: 2, capabilities: Phronomy::Storage::Backend::REQUIRED_CAPABILITIES,
|
|
30
|
+
surfaces: surfaces.to_h { |type, names| [type.name, names.sort.to_h { |name| [name, type.instance_method(name).parameters] }] }}
|
|
31
|
+
json = JSON.pretty_generate(snapshot) + "\n"
|
|
32
|
+
if ARGV.include?("--write")
|
|
33
|
+
File.write(File.expand_path("../spec/fixtures/storage_spi_v2_snapshot.json", __dir__), json)
|
|
34
|
+
else
|
|
35
|
+
puts json
|
|
36
|
+
end
|
data/sig/phronomy/agent.rbs
CHANGED
|
@@ -190,7 +190,6 @@ module Phronomy
|
|
|
190
190
|
def self.max_iterations: (?Integer value) -> Integer
|
|
191
191
|
def self.cache_instructions: (?bool enabled) -> bool?
|
|
192
192
|
def self.max_output_tokens: (?Integer value) -> Integer?
|
|
193
|
-
def self.context_window: (?Integer value) -> Integer?
|
|
194
193
|
def self.context_policy: () -> ContextPolicy
|
|
195
194
|
| (ContextPolicy policy) -> ContextPolicy
|
|
196
195
|
def self.agent_definition: () -> Hash[Symbol, untyped]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Phronomy
|
|
2
|
+
# Internal Engine contract (ADR-042); not an application extension SPI.
|
|
3
|
+
class ExecutionReceiver
|
|
4
|
+
def self.for: (EventLoop event_loop) -> instance
|
|
5
|
+
def self.existing_for: (Runtime runtime) -> instance?
|
|
6
|
+
def initialize: (event_loop: EventLoop) -> void
|
|
7
|
+
def __bound_to?: (EventLoop event_loop) -> bool
|
|
8
|
+
def idle?: () -> bool
|
|
9
|
+
def deliver: (untyped message) -> untyped
|
|
10
|
+
def shutdown: (error: Exception?) -> untyped
|
|
11
|
+
def session_retired: (String fsm_session_id, reason: Symbol) -> untyped
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def synchronize: [V] () { () -> V } -> V
|
|
16
|
+
def admit: [V] () { () -> V } -> V
|
|
17
|
+
def post_message: (untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
|
|
18
|
+
def assert_event_loop_thread!: () -> void
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class EventLoop
|
|
22
|
+
def __execution_receiver: (key: untyped) -> ExecutionReceiver?
|
|
23
|
+
def __register_execution_receiver: (key: untyped, receiver: ExecutionReceiver) -> ExecutionReceiver
|
|
24
|
+
def __synchronize_execution_state: [V] () { () -> V } -> V
|
|
25
|
+
def __admit_execution: [V] (ExecutionReceiver receiver) { () -> V } -> V
|
|
26
|
+
def __post_execution: (ExecutionReceiver receiver, untyped message, ?admission: bool, ?completion: TaskResult[untyped]?) -> bool
|
|
27
|
+
def __route_execution_event: (ExecutionReceiver receiver) { () -> untyped } -> bool
|
|
28
|
+
def __receiver_cleanup_complete?: () -> bool
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Runtime
|
|
32
|
+
def __event_loop_if_initialized: () -> EventLoop?
|
|
33
|
+
end
|
|
34
|
+
end
|
data/sig/phronomy/handoff.rbs
CHANGED
|
@@ -25,14 +25,16 @@ module Phronomy
|
|
|
25
25
|
def selectable_categories: () -> Array[Symbol]
|
|
26
26
|
def to_h: () -> Hash[String, Hash[String, String]]
|
|
27
27
|
end
|
|
28
|
+
end
|
|
28
29
|
|
|
30
|
+
module MultiAgent
|
|
29
31
|
class HandoffRunner
|
|
30
32
|
MAX_HANDOFFS: Integer
|
|
31
33
|
|
|
32
34
|
attr_reader main_agent: ::Phronomy::Agent::Base
|
|
33
|
-
attr_reader handoffs: Array[Handoff]
|
|
35
|
+
attr_reader handoffs: Array[::Phronomy::Agent::Handoff]
|
|
34
36
|
|
|
35
|
-
def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[Handoff]) -> void
|
|
37
|
+
def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[::Phronomy::Agent::Handoff]) -> void
|
|
36
38
|
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
37
39
|
def result: (String execution_id) -> Hash[Symbol, untyped]
|
|
38
40
|
def cancel: (String execution_id) -> Hash[Symbol, untyped]
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
module Phronomy
|
|
2
2
|
module MultiAgent
|
|
3
|
+
class SharedState
|
|
4
|
+
class KnowledgeStore
|
|
5
|
+
def self.new: () -> instance
|
|
6
|
+
def read_all: () -> Array[Hash[Symbol, untyped]]
|
|
7
|
+
def write: (agent: untyped, content: untyped, cycle: untyped) -> nil
|
|
8
|
+
def size: () -> Integer
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.new: () -> instance
|
|
12
|
+
def self.member: (singleton(::Phronomy::Agent::Base) klass, ?instruction: untyped) -> Array[Hash[Symbol, untyped]]
|
|
13
|
+
def self.coordination: (?untyped text) -> untyped
|
|
14
|
+
def self.max_cycles: (?untyped value) -> Integer?
|
|
15
|
+
def self.timeout: (?untyped value) -> Float?
|
|
16
|
+
def self.terminate_when: () ?{ (KnowledgeStore) -> untyped } -> untyped
|
|
17
|
+
def self.aggregate: () ?{ (KnowledgeStore) -> untyped } -> untyped
|
|
18
|
+
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
19
|
+
end
|
|
20
|
+
|
|
3
21
|
class Orchestrator < ::Phronomy::Agent::Base
|
|
4
22
|
def self.subagent: (Symbol | String name, singleton(::Phronomy::Agent::Base) agent_class, ?on_error: Symbol, ?inherit_knowledge: bool) -> untyped
|
|
5
23
|
def self.registered_subagents: () -> Hash[Symbol | String, untyped]
|