phronomy 0.21.0 → 0.23.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 +3 -4
- data/CHANGELOG.md +200 -10
- data/CONTRIBUTING.md +81 -9
- data/README.md +20 -0
- data/VERIFY.sh +587 -0
- data/benchmark/bench_agent_invoke.rb +2 -2
- data/benchmark/bench_context_assembler.rb +39 -68
- data/benchmark/bench_regression.rb +2 -2
- data/docs/architecture/agent-context.md +174 -0
- data/docs/architecture/before-llm-input.md +78 -0
- data/docs/architecture/context-management.md +232 -0
- data/docs/architecture/knowledge-and-rag.md +130 -0
- data/docs/architecture/multi-agent-handoff.md +152 -0
- data/docs/architecture/persistence.md +175 -0
- data/docs/architecture/removed/agent-context.md +72 -0
- data/docs/architecture/security-boundaries.md +173 -0
- data/docs/architecture/tracing.md +194 -0
- data/docs/architecture.md +82 -0
- data/docs/archive/design/archived/04_api_design.md +507 -0
- data/docs/archive/design/archived/09_guardrails.md +186 -0
- data/docs/archive/design/archived/17_rails_integration.md +175 -0
- data/docs/archive/design/historical/00_design_philosophy.md +122 -0
- data/docs/archive/design/historical/01_rubyllm_evaluation.md +178 -0
- data/docs/archive/design/historical/06_design_decisions.md +143 -0
- data/docs/changelog/0.14-and-earlier.md +1 -1
- data/docs/decisions/001-rubyllm-as-provider-layer.md +6 -1
- data/docs/decisions/002-workflow-context-immutability.md +26 -1
- data/docs/decisions/006-no-built-in-guardrails.md +2 -1
- data/docs/decisions/012-canonical-execution-log-and-context-policy.md +120 -38
- data/docs/decisions/014-unified-persistence-durable-state.md +9 -2
- data/docs/decisions/016-semantic-multi-agent-handoff.md +112 -0
- data/docs/decisions/017-design-authority-and-adr-governance.md +200 -0
- data/docs/decisions/018-durability-guarantees-and-failure-model.md +488 -0
- data/docs/decisions/019-filter-contract-and-security-boundaries.md +229 -0
- data/docs/decisions/020-canonical-workflow-instance-identity.md +177 -0
- data/docs/decisions/021-generic-agent-invocation-identity-removal.md +119 -0
- data/docs/decisions/022-agent-execution-parent-identity-and-runtime-routing-boundary.md +193 -0
- data/docs/decisions/023-fsm-session-incarnation-identity-and-routing.md +139 -0
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +188 -0
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +249 -0
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +257 -0
- data/docs/decisions/027-llm-adapter-provider-boundary.md +93 -0
- data/docs/decisions/README.md +172 -0
- data/docs/features.md +31 -11
- data/docs/getting-started.md +91 -50
- data/docs/migrations/0.19.md +14 -7
- data/docs/migrations/0.22.md +390 -0
- data/docs/persistence-backends.md +88 -38
- data/docs/runtime-and-concurrency.md +227 -33
- data/examples/README.md +13 -0
- data/lib/phronomy/agent/agent_execution.rb +19 -15
- data/lib/phronomy/agent/agent_invocation.rb +288 -93
- data/lib/phronomy/agent/agent_invocation_session_builder.rb +236 -202
- data/lib/phronomy/agent/agent_root.rb +3 -3
- data/lib/phronomy/agent/approval_evaluation_request.rb +37 -19
- data/lib/phronomy/agent/async_event_api.rb +150 -67
- data/lib/phronomy/agent/base.rb +388 -181
- data/lib/phronomy/agent/concerns/before_llm_input.rb +1 -1
- data/lib/phronomy/agent/context_assembler.rb +437 -178
- data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
- data/lib/phronomy/agent/context_plan.rb +18 -13
- data/lib/phronomy/agent/context_plan_validator.rb +246 -88
- data/lib/phronomy/agent/context_policies/default.rb +123 -34
- data/lib/phronomy/agent/context_policy.rb +109 -3
- data/lib/phronomy/agent/context_policy_input.rb +244 -0
- data/lib/phronomy/agent/context_policy_input_builder.rb +241 -0
- data/lib/phronomy/agent/execution_coordinator.rb +1975 -587
- data/lib/phronomy/agent/journal_record.rb +17 -4
- data/lib/phronomy/agent/llm_input_build_context.rb +1 -1
- data/lib/phronomy/agent/llm_input_manifest.rb +277 -2
- data/lib/phronomy/agent/llm_operation_result.rb +12 -7
- data/lib/phronomy/agent/phase_machine_builder.rb +19 -7
- data/lib/phronomy/agent/provider_call_outcome.rb +23 -7
- data/lib/phronomy/agent/recovery_coordinator/continuation.rb +271 -0
- data/lib/phronomy/agent/recovery_coordinator/installation.rb +427 -0
- data/lib/phronomy/agent/recovery_coordinator/resolution.rb +635 -0
- data/lib/phronomy/agent/recovery_coordinator.rb +211 -0
- data/lib/phronomy/agent/recovery_support.rb +512 -0
- data/lib/phronomy/agent/ruby_llm_materializer.rb +22 -13
- data/lib/phronomy/agent/selection/candidate.rb +53 -0
- data/lib/phronomy/agent/selection/constraint.rb +49 -0
- data/lib/phronomy/agent/shared_state.rb +38 -1
- data/lib/phronomy/agent/tool_approval_request.rb +33 -5
- data/lib/phronomy/agent/tool_definition_set.rb +49 -3
- data/lib/phronomy/agent/tool_invocation.rb +336 -102
- data/lib/phronomy/agent/tool_invocation_session_builder.rb +49 -45
- data/lib/phronomy/agent.rb +20 -2
- data/lib/phronomy/agent_already_exists_error.rb +5 -0
- data/lib/phronomy/agent_purged_error.rb +5 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +17 -3
- data/lib/phronomy/engine/concurrency/physical_completion_task.rb +135 -0
- data/lib/phronomy/engine/event_loop.rb +622 -63
- data/lib/phronomy/engine/fsm_session.rb +194 -21
- data/lib/phronomy/engine/runtime/agent_ownership_registry.rb +352 -0
- data/lib/phronomy/engine/runtime.rb +77 -20
- data/lib/phronomy/generator_verifier.rb +12 -14
- data/lib/phronomy/invocation_context.rb +9 -29
- data/lib/phronomy/multi_agent/admission_registry.rb +51 -0
- data/lib/phronomy/multi_agent/coordination_state.rb +18 -0
- data/lib/phronomy/multi_agent/coordinator.rb +154 -0
- data/lib/phronomy/multi_agent/execution_coordinator.rb +116 -0
- data/lib/phronomy/multi_agent/fan_out_invocation.rb +24 -33
- data/lib/phronomy/multi_agent/fan_out_session_builder.rb +12 -19
- data/lib/phronomy/multi_agent/handoff.rb +24 -45
- data/lib/phronomy/multi_agent/handoff_capability_factory.rb +87 -0
- data/lib/phronomy/multi_agent/handoff_context.rb +95 -0
- data/lib/phronomy/multi_agent/handoff_policy.rb +137 -0
- data/lib/phronomy/multi_agent/handoff_projection.rb +191 -0
- data/lib/phronomy/multi_agent/handoff_request.rb +45 -0
- data/lib/phronomy/multi_agent/orchestrator.rb +12 -15
- data/lib/phronomy/multi_agent/runner.rb +98 -0
- data/lib/phronomy/persistence/durable_codec.rb +646 -0
- data/lib/phronomy/persistence/durable_record.rb +117 -0
- data/lib/phronomy/persistence/in_memory.rb +210 -134
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
- data/lib/phronomy/persistence/repository_facades.rb +316 -0
- data/lib/phronomy/persistence.rb +81 -41
- data/lib/phronomy/recovery.rb +186 -0
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +19 -19
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
- data/lib/phronomy/tracing/automatic.rb +176 -0
- data/lib/phronomy/tracing/base.rb +11 -2
- data/lib/phronomy/tracing/langfuse_tracer.rb +20 -12
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow.rb +3 -6
- data/lib/phronomy/workflow_context.rb +14 -5
- data/lib/phronomy/workflow_recovery.rb +123 -0
- data/lib/phronomy/workflow_runner.rb +468 -256
- data/lib/phronomy.rb +6 -0
- data/scripts/api_snapshot.rb +12 -0
- data/sig/phronomy/agent.rbs +209 -7
- data/sig/phronomy/multi_agent.rbs +39 -0
- data/sig/phronomy/persistence.rbs +62 -4
- data/sig/phronomy/runtime.rbs +1 -4
- data/sig/phronomy/workflow.rbs +2 -2
- data/sig/phronomy.rbs +10 -0
- metadata +65 -17
- data/examples/workflows/agent_event_mapping.rb +0 -104
- data/examples/workflows/generic_task_event_mapping.rb +0 -66
- data/lib/phronomy/agent/activation_registry.rb +0 -28
- data/lib/phronomy/agent/agent_execution_activation.rb +0 -172
- data/lib/phronomy/agent/context_candidate.rb +0 -47
- data/lib/phronomy/agent/context_parts/budget/token_budget_packer.rb +0 -53
- data/lib/phronomy/agent/context_parts/requirements/required_context_resolver.rb +0 -56
- data/lib/phronomy/agent/context_parts/selectors/recent_first_selector.rb +0 -30
- data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +0 -118
- data/lib/phronomy/agent/context_policy_descriptor.rb +0 -49
- data/lib/phronomy/agent/context_policy_registry.rb +0 -46
- data/lib/phronomy/agent/context_request.rb +0 -35
- data/lib/phronomy/agent/context_selection_unit.rb +0 -38
- data/lib/phronomy/agent/derived_content_spec.rb +0 -34
- data/lib/phronomy/agent/runner.rb +0 -97
|
@@ -8,19 +8,19 @@ module Phronomy
|
|
|
8
8
|
LIFECYCLE_STATUSES = %i[idle active suspended closed invalidated].freeze
|
|
9
9
|
|
|
10
10
|
ATTRIBUTES = %i[
|
|
11
|
-
agent_id agent_definition_id
|
|
11
|
+
agent_id agent_definition_id agent_definition_version agent_revision
|
|
12
12
|
context_revision journal_position lifecycle_status transcript_generation
|
|
13
13
|
created_at updated_at metadata
|
|
14
14
|
].freeze
|
|
15
15
|
|
|
16
16
|
attr_reader(*ATTRIBUTES)
|
|
17
17
|
|
|
18
|
-
def self.create(agent_id:, agent_definition_id:,
|
|
18
|
+
def self.create(agent_id:, agent_definition_id:, agent_definition_version:, metadata: {})
|
|
19
19
|
now = Time.now.utc.iso8601(6)
|
|
20
20
|
new(
|
|
21
21
|
agent_id: agent_id,
|
|
22
22
|
agent_definition_id: agent_definition_id,
|
|
23
|
-
|
|
23
|
+
agent_definition_version: agent_definition_version,
|
|
24
24
|
agent_revision: 0,
|
|
25
25
|
context_revision: 0,
|
|
26
26
|
journal_position: 0,
|
|
@@ -2,17 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
module Agent
|
|
5
|
-
#
|
|
5
|
+
# Value-oriented input passed to Tool approval policy callables.
|
|
6
6
|
#
|
|
7
7
|
# This object intentionally contains the internal, validated arguments used
|
|
8
|
-
# for policy evaluation. It
|
|
8
|
+
# for policy evaluation. It carries Agent identity metadata and Tool
|
|
9
|
+
# description data only; it never exposes live Agent or Tool objects.
|
|
10
|
+
#
|
|
11
|
+
# Hash, Array, and String values are recursively copied/frozen. Other
|
|
12
|
+
# application-owned opaque values remain application-owned; complete
|
|
13
|
+
# value-type enforcement for those objects is outside ACS-11.
|
|
14
|
+
#
|
|
15
|
+
# This object must not be exposed directly to Application UI.
|
|
9
16
|
# Use {ToolApprovalRequest} for notifications.
|
|
10
17
|
#
|
|
11
18
|
# @api public
|
|
12
19
|
class ApprovalEvaluationRequest
|
|
13
|
-
attr_reader :
|
|
14
|
-
:
|
|
15
|
-
:
|
|
20
|
+
attr_reader :agent_id,
|
|
21
|
+
:agent_definition_id,
|
|
22
|
+
:agent_definition_version,
|
|
23
|
+
:execution_id,
|
|
16
24
|
:tool_name,
|
|
17
25
|
:tool_schema,
|
|
18
26
|
:tool_invocation_id,
|
|
@@ -27,9 +35,10 @@ module Phronomy
|
|
|
27
35
|
VALID_DECISIONS = %i[allow require_approval reject].freeze
|
|
28
36
|
|
|
29
37
|
def initialize(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
agent_id:,
|
|
39
|
+
agent_definition_id:,
|
|
40
|
+
agent_definition_version:,
|
|
41
|
+
execution_id:,
|
|
33
42
|
tool_name:,
|
|
34
43
|
tool_schema:,
|
|
35
44
|
tool_invocation_id:,
|
|
@@ -41,9 +50,21 @@ module Phronomy
|
|
|
41
50
|
metadata: {},
|
|
42
51
|
default_decision: nil
|
|
43
52
|
)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
if agent_id.nil? || agent_id.to_s.empty?
|
|
54
|
+
raise ArgumentError, "ApprovalEvaluationRequest requires agent_id"
|
|
55
|
+
end
|
|
56
|
+
if agent_definition_id.nil? || agent_definition_id.to_s.empty?
|
|
57
|
+
raise ArgumentError,
|
|
58
|
+
"ApprovalEvaluationRequest requires agent_definition_id"
|
|
59
|
+
end
|
|
60
|
+
if execution_id.nil? || execution_id.to_s.empty?
|
|
61
|
+
raise ArgumentError, "ApprovalEvaluationRequest requires execution_id"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@agent_id = agent_id.to_s.freeze
|
|
65
|
+
@agent_definition_id = agent_definition_id.to_s.freeze
|
|
66
|
+
@agent_definition_version = Integer(agent_definition_version)
|
|
67
|
+
@execution_id = execution_id.to_s.freeze
|
|
47
68
|
@tool_name = tool_name.to_s.freeze
|
|
48
69
|
@tool_schema = immutable_copy(tool_schema)
|
|
49
70
|
@tool_invocation_id = tool_invocation_id.to_s.freeze
|
|
@@ -61,9 +82,10 @@ module Phronomy
|
|
|
61
82
|
# @api private
|
|
62
83
|
def with(facts: @facts, default_decision: @default_decision)
|
|
63
84
|
self.class.new(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
85
|
+
agent_id: @agent_id,
|
|
86
|
+
agent_definition_id: @agent_definition_id,
|
|
87
|
+
agent_definition_version: @agent_definition_version,
|
|
88
|
+
execution_id: @execution_id,
|
|
67
89
|
tool_name: @tool_name,
|
|
68
90
|
tool_schema: @tool_schema,
|
|
69
91
|
tool_invocation_id: @tool_invocation_id,
|
|
@@ -90,11 +112,7 @@ module Phronomy
|
|
|
90
112
|
when String
|
|
91
113
|
value.dup.freeze
|
|
92
114
|
else
|
|
93
|
-
|
|
94
|
-
value.frozen? ? value : value.dup.freeze
|
|
95
|
-
rescue TypeError
|
|
96
|
-
value
|
|
97
|
-
end
|
|
115
|
+
value
|
|
98
116
|
end
|
|
99
117
|
end
|
|
100
118
|
end
|
|
@@ -2,98 +2,85 @@
|
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
module Agent
|
|
5
|
-
# Public Agent execution
|
|
6
|
-
#
|
|
5
|
+
# Public Agent execution facade.
|
|
6
|
+
#
|
|
7
|
+
# CG-09 clean break:
|
|
8
|
+
# - application event listeners are bound to the live Agent incarnation at
|
|
9
|
+
# new/create/load time;
|
|
10
|
+
# - invoke/invoke_async/stream/stream_async do not accept per-call event
|
|
11
|
+
# listeners or listener blocks;
|
|
12
|
+
# - approval notifications share the Agent listener as :approval_required;
|
|
13
|
+
# - Recovery resolution uses resolve/resolve_async.
|
|
7
14
|
module AsyncEventApi
|
|
8
|
-
def invoke(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
def invoke(
|
|
16
|
+
input,
|
|
17
|
+
config: {},
|
|
18
|
+
invocation_context: nil,
|
|
19
|
+
**removed_options,
|
|
20
|
+
&removed_block
|
|
21
|
+
)
|
|
22
|
+
_reject_removed_invocation_listener_arguments!(removed_options, removed_block)
|
|
23
|
+
config = _prepare_invocation_config(config, invocation_context)
|
|
12
24
|
_check_event_loop_reentrancy(:invoke, :invoke_async)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
).wait_result
|
|
20
|
-
[result, result[:usage]]
|
|
21
|
-
end
|
|
25
|
+
_start_agent_operation(
|
|
26
|
+
input,
|
|
27
|
+
config: config,
|
|
28
|
+
mode: :invoke,
|
|
29
|
+
listener: _phronomy_event_listener
|
|
30
|
+
).wait_result
|
|
22
31
|
end
|
|
23
32
|
|
|
24
33
|
def invoke_async(
|
|
25
34
|
input,
|
|
26
|
-
thread_id: nil,
|
|
27
35
|
config: {},
|
|
28
36
|
invocation_context: nil,
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
**removed_options,
|
|
38
|
+
&removed_block
|
|
31
39
|
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
approval = _approval_configuration_snapshot(on_tool_approval_required)
|
|
36
|
-
execution_coordinator.start(
|
|
40
|
+
_reject_removed_invocation_listener_arguments!(removed_options, removed_block)
|
|
41
|
+
config = _prepare_invocation_config(config, invocation_context)
|
|
42
|
+
_start_agent_operation(
|
|
37
43
|
input,
|
|
38
|
-
thread_id: thread_id,
|
|
39
44
|
config: config,
|
|
40
45
|
mode: :invoke,
|
|
41
|
-
|
|
42
|
-
approval_listener: approval[:listener],
|
|
43
|
-
on_event: on_event
|
|
46
|
+
listener: _phronomy_event_listener
|
|
44
47
|
)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
def stream(
|
|
48
51
|
input,
|
|
49
|
-
thread_id: nil,
|
|
50
52
|
config: {},
|
|
51
53
|
invocation_context: nil,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
&block
|
|
54
|
+
**removed_options,
|
|
55
|
+
&removed_block
|
|
55
56
|
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
thread_id, config = _apply_invocation_context(thread_id, config, invocation_context)
|
|
60
|
-
end
|
|
57
|
+
_reject_removed_invocation_listener_arguments!(removed_options, removed_block)
|
|
58
|
+
listener = _required_stream_listener!(:stream)
|
|
59
|
+
config = _prepare_invocation_config(config, invocation_context)
|
|
61
60
|
_check_event_loop_reentrancy(:stream, :stream_async)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
on_event: listener
|
|
69
|
-
).wait_result
|
|
70
|
-
[result, result[:usage]]
|
|
71
|
-
end
|
|
61
|
+
_start_agent_operation(
|
|
62
|
+
input,
|
|
63
|
+
config: config,
|
|
64
|
+
mode: :stream,
|
|
65
|
+
listener: listener
|
|
66
|
+
).wait_result
|
|
72
67
|
end
|
|
73
68
|
|
|
74
69
|
def stream_async(
|
|
75
70
|
input,
|
|
76
|
-
thread_id: nil,
|
|
77
71
|
config: {},
|
|
78
72
|
invocation_context: nil,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
&block
|
|
73
|
+
**removed_options,
|
|
74
|
+
&removed_block
|
|
82
75
|
)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
end
|
|
88
|
-
approval = _approval_configuration_snapshot(on_tool_approval_required)
|
|
89
|
-
execution_coordinator.start(
|
|
76
|
+
_reject_removed_invocation_listener_arguments!(removed_options, removed_block)
|
|
77
|
+
listener = _required_stream_listener!(:stream_async)
|
|
78
|
+
config = _prepare_invocation_config(config, invocation_context)
|
|
79
|
+
_start_agent_operation(
|
|
90
80
|
input,
|
|
91
|
-
thread_id: thread_id,
|
|
92
81
|
config: config,
|
|
93
82
|
mode: :stream,
|
|
94
|
-
|
|
95
|
-
approval_listener: approval[:listener],
|
|
96
|
-
on_event: listener
|
|
83
|
+
listener: listener
|
|
97
84
|
)
|
|
98
85
|
end
|
|
99
86
|
|
|
@@ -108,7 +95,14 @@ module Phronomy
|
|
|
108
95
|
end
|
|
109
96
|
|
|
110
97
|
def approve_async(execution_id, approval_request_id:, approved: true, config: {})
|
|
111
|
-
|
|
98
|
+
_reject_removed_generic_identity_keys!(config)
|
|
99
|
+
owner = Phronomy::Runtime.instance.__agent_execution_owner(execution_id)
|
|
100
|
+
coordinator = if owner&.agent&.equal?(self)
|
|
101
|
+
owner.coordinator
|
|
102
|
+
else
|
|
103
|
+
execution_coordinator_for(config)
|
|
104
|
+
end
|
|
105
|
+
coordinator.resume(
|
|
112
106
|
execution_id,
|
|
113
107
|
approval_request_id: approval_request_id,
|
|
114
108
|
approved: approved,
|
|
@@ -116,17 +110,106 @@ module Phronomy
|
|
|
116
110
|
)
|
|
117
111
|
end
|
|
118
112
|
|
|
113
|
+
def resolve(
|
|
114
|
+
execution_id,
|
|
115
|
+
expected_execution_revision:,
|
|
116
|
+
subject:,
|
|
117
|
+
outcome:,
|
|
118
|
+
result: Phronomy::Recovery::MISSING,
|
|
119
|
+
error: Phronomy::Recovery::MISSING
|
|
120
|
+
)
|
|
121
|
+
_check_event_loop_reentrancy(:resolve, :resolve_async)
|
|
122
|
+
resolve_async(
|
|
123
|
+
execution_id,
|
|
124
|
+
expected_execution_revision: expected_execution_revision,
|
|
125
|
+
subject: subject,
|
|
126
|
+
outcome: outcome,
|
|
127
|
+
result: result,
|
|
128
|
+
error: error
|
|
129
|
+
).wait_result
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def resolve_async(
|
|
133
|
+
execution_id,
|
|
134
|
+
expected_execution_revision:,
|
|
135
|
+
subject:,
|
|
136
|
+
outcome:,
|
|
137
|
+
result: Phronomy::Recovery::MISSING,
|
|
138
|
+
error: Phronomy::Recovery::MISSING
|
|
139
|
+
)
|
|
140
|
+
Phronomy::Agent::RecoveryCoordinator.new(self).resolve(
|
|
141
|
+
execution_id,
|
|
142
|
+
expected_execution_revision: expected_execution_revision,
|
|
143
|
+
subject: subject,
|
|
144
|
+
outcome: outcome,
|
|
145
|
+
result: result,
|
|
146
|
+
error: error
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
119
150
|
private
|
|
120
151
|
|
|
152
|
+
# Framework-private execution-local event routing. This is intentionally
|
|
153
|
+
# not a public compatibility path for invoke_async(..., on_event:).
|
|
154
|
+
def __invoke_async_with_event_sink(
|
|
155
|
+
input,
|
|
156
|
+
on_event:, config: {},
|
|
157
|
+
invocation_context: nil
|
|
158
|
+
)
|
|
159
|
+
raise ArgumentError, "on_event is required" unless on_event
|
|
160
|
+
|
|
161
|
+
config = _prepare_invocation_config(config, invocation_context)
|
|
162
|
+
_start_agent_operation(
|
|
163
|
+
input,
|
|
164
|
+
config: config,
|
|
165
|
+
mode: :invoke,
|
|
166
|
+
listener: on_event
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def _start_agent_operation(input, config:, mode:, listener:)
|
|
171
|
+
approval = _approval_configuration_snapshot(nil)
|
|
172
|
+
execution_coordinator_for(config).start(
|
|
173
|
+
input,
|
|
174
|
+
config: config.merge(phronomy_recovery_mode: mode.to_sym),
|
|
175
|
+
mode: mode,
|
|
176
|
+
approval_policy: approval[:policy],
|
|
177
|
+
approval_listener: nil,
|
|
178
|
+
on_event: listener
|
|
179
|
+
)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def _required_stream_listener!(method_name)
|
|
183
|
+
listener = _phronomy_event_listener
|
|
184
|
+
return listener if listener
|
|
185
|
+
|
|
186
|
+
raise ArgumentError,
|
|
187
|
+
"#{method_name} requires an Agent on_event listener registered at new/create/load"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def _reject_removed_invocation_listener_arguments!(options, block)
|
|
191
|
+
if block
|
|
192
|
+
raise ArgumentError,
|
|
193
|
+
"invoke/stream blocks no longer register Agent events; register the listener at new/create/load"
|
|
194
|
+
end
|
|
195
|
+
return if options.empty?
|
|
196
|
+
|
|
197
|
+
removed = options.keys.map(&:inspect).join(", ")
|
|
198
|
+
raise ArgumentError,
|
|
199
|
+
"removed per-invocation Agent option(s): #{removed}; register on_event at new/create/load"
|
|
200
|
+
end
|
|
201
|
+
|
|
121
202
|
def execution_coordinator
|
|
122
203
|
@execution_coordinator ||= Agent::ExecutionCoordinator.new(self)
|
|
123
204
|
end
|
|
124
205
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
206
|
+
def execution_coordinator_for(config)
|
|
207
|
+
multi_agent = config.key?(:phronomy_handoff_bindings) ||
|
|
208
|
+
config.key?(:phronomy_handoff_context)
|
|
209
|
+
return execution_coordinator unless multi_agent
|
|
210
|
+
|
|
211
|
+
@multi_agent_execution_coordinator ||=
|
|
212
|
+
Phronomy::MultiAgent::ExecutionCoordinator.new(self)
|
|
130
213
|
end
|
|
131
214
|
end
|
|
132
215
|
end
|