phronomy 0.23.0 → 0.24.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 +2 -2
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +2 -2
- data/README.md +1 -1
- data/docs/architecture/multi-agent-handoff.md +35 -40
- data/docs/architecture/persistence.md +19 -8
- data/docs/architecture.md +8 -1
- data/docs/decisions/016-semantic-multi-agent-handoff.md +3 -1
- data/docs/decisions/028-preparing-recovery-replay-contract.md +106 -0
- data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +220 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +235 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +301 -0
- data/docs/decisions/README.md +5 -1
- data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +33 -0
- data/docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md +191 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +862 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +106 -0
- data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +179 -0
- data/docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md +302 -0
- data/docs/features.md +35 -1
- data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
- data/docs/persistence-backends.md +42 -3
- data/lib/phronomy/agent/agent_execution.rb +2 -2
- data/lib/phronomy/agent/agent_invocation.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +18 -1
- data/lib/phronomy/agent/base.rb +28 -0
- data/lib/phronomy/agent/context_assembler.rb +1 -1
- data/lib/phronomy/agent/exact_execution.rb +153 -0
- data/lib/phronomy/agent/execution_cancellation.rb +25 -0
- data/lib/phronomy/agent/execution_coordinator.rb +484 -27
- data/lib/phronomy/{multi_agent → agent}/handoff.rb +4 -4
- data/lib/phronomy/{multi_agent → agent}/handoff_capability_factory.rb +3 -45
- data/lib/phronomy/{multi_agent → agent}/handoff_context.rb +26 -1
- data/lib/phronomy/{multi_agent/execution_coordinator.rb → agent/handoff_execution_coordinator.rb} +32 -5
- data/lib/phronomy/{multi_agent → agent}/handoff_policy.rb +7 -1
- data/lib/phronomy/{multi_agent → agent}/handoff_projection.rb +18 -2
- data/lib/phronomy/{multi_agent → agent}/handoff_request.rb +2 -2
- data/lib/phronomy/agent/handoff_runner.rb +178 -0
- data/lib/phronomy/agent/handoff_state.rb +43 -0
- data/lib/phronomy/agent/recovery_coordinator/continuation.rb +114 -211
- data/lib/phronomy/agent/recovery_coordinator/installation.rb +84 -130
- data/lib/phronomy/agent/recovery_coordinator/resolution.rb +76 -200
- data/lib/phronomy/agent/recovery_coordinator.rb +11 -5
- data/lib/phronomy/agent/recovery_support.rb +15 -23
- data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -8
- data/lib/phronomy/agent/tool_invocation.rb +4 -2
- data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
- data/lib/phronomy/engine/runtime.rb +16 -1
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
- data/lib/phronomy/multi_agent/orchestrator.rb +59 -11
- data/lib/phronomy/multi_agent/team_coordinator.rb +473 -125
- data/lib/phronomy/multi_agent/team_execution.rb +44 -0
- data/lib/phronomy/multi_agent/team_root.rb +41 -0
- data/lib/phronomy/persistence/durable_codec.rb +60 -0
- data/lib/phronomy/persistence/in_memory.rb +264 -2
- data/lib/phronomy/persistence/repository_facades.rb +221 -2
- data/lib/phronomy/persistence.rb +95 -1
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +1 -0
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +137 -0
- data/lib/phronomy/testing/persistence_contract.rb +5 -0
- data/lib/phronomy/tools/agent.rb +1 -1
- data/lib/phronomy/version.rb +1 -1
- data/scripts/api_snapshot.rb +3 -3
- data/sig/phronomy/handoff.rbs +41 -0
- data/sig/phronomy/multi_agent.rbs +28 -32
- data/sig/phronomy/persistence.rbs +64 -3
- metadata +30 -12
- data/lib/phronomy/multi_agent/coordination_state.rb +0 -18
- data/lib/phronomy/multi_agent/coordinator.rb +0 -154
- data/lib/phronomy/multi_agent/runner.rb +0 -98
data/lib/phronomy/persistence.rb
CHANGED
|
@@ -45,6 +45,89 @@ module Phronomy
|
|
|
45
45
|
# @api public
|
|
46
46
|
attr_reader :workflow_states
|
|
47
47
|
|
|
48
|
+
# Purpose-specific durable Handoff and Team repositories in atomic_all.
|
|
49
|
+
# @api public
|
|
50
|
+
attr_reader :handoff_states, :teams, :team_executions
|
|
51
|
+
|
|
52
|
+
# Read-only exact Agent execution result; never creates a live Agent owner.
|
|
53
|
+
# Result is nil until a result_ref exists; errors remain canonical data.
|
|
54
|
+
# @api public
|
|
55
|
+
def execution_result(execution_id)
|
|
56
|
+
assert_observation_thread!
|
|
57
|
+
execution = executions.load(execution_id)
|
|
58
|
+
{
|
|
59
|
+
execution_id: execution.execution_id, agent_id: execution.agent_id,
|
|
60
|
+
status: execution.status, phase: execution.phase,
|
|
61
|
+
result_ref: execution.result_ref, error_ref: execution.error_ref,
|
|
62
|
+
result: execution.result_ref && contents.fetch_text(execution.result_ref),
|
|
63
|
+
error: execution.error_ref && contents.fetch_json(execution.error_ref)
|
|
64
|
+
}.then { |value| Phronomy::Agent::Immutable.copy(value) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Follows one exact Handoff turn without loading any Agent or graph.
|
|
68
|
+
# A committed absent Target reservation remains active; failed reads raise.
|
|
69
|
+
# @api public
|
|
70
|
+
def handoff_result(execution_id, main_agent_id: nil)
|
|
71
|
+
assert_observation_thread!
|
|
72
|
+
anchor = main_agent_id&.to_s
|
|
73
|
+
seen = {}
|
|
74
|
+
current = execution_id.to_s
|
|
75
|
+
reserved_agent_id = nil
|
|
76
|
+
loop do
|
|
77
|
+
raise Phronomy::Persistence::SerializationError, "Cyclic durable Handoff chain" if seen[current]
|
|
78
|
+
seen[current] = true
|
|
79
|
+
begin
|
|
80
|
+
execution = executions.load(current)
|
|
81
|
+
rescue Phronomy::Persistence::NotFoundError
|
|
82
|
+
routing = handoff_states.load(anchor)
|
|
83
|
+
if routing && Array(routing.metadata["cancelled_execution_ids"]).include?(current)
|
|
84
|
+
return {execution_id: current, agent_id: reserved_agent_id, status: :cancelled, result: nil, error: nil}.freeze
|
|
85
|
+
end
|
|
86
|
+
if reserved_agent_id && routing && routing.phase != "stable" && routing.pending_target_execution_id == current
|
|
87
|
+
return {execution_id: current, agent_id: reserved_agent_id, status: :active,
|
|
88
|
+
phase: :target_pending, reserved: true, result: nil, error: nil}.freeze
|
|
89
|
+
end
|
|
90
|
+
raise
|
|
91
|
+
end
|
|
92
|
+
anchor ||= execution.metadata.dig("coordination", "main_agent_id")
|
|
93
|
+
unless anchor && execution.metadata.dig("coordination", "main_agent_id") == anchor
|
|
94
|
+
raise Phronomy::Persistence::ConflictError, "Execution does not belong to this Handoff anchor"
|
|
95
|
+
end
|
|
96
|
+
return execution_result(current) unless execution.status == :handed_off
|
|
97
|
+
reserved_agent_id = execution.metadata.fetch("handoff_target_agent_id")
|
|
98
|
+
current = execution.metadata.fetch("handoff_target_execution_id")
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Lists retained active and terminal executions in lexical ID order.
|
|
103
|
+
# after is an exclusive ID cursor; discovery does not imply request dedup.
|
|
104
|
+
# @api public
|
|
105
|
+
def list_executions(agent_id, after: nil, limit: 100)
|
|
106
|
+
assert_observation_thread!
|
|
107
|
+
executions.list(agent_id, after: after, limit: limit)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Read-only exact Team result, independent of current Team class/Proc wiring.
|
|
111
|
+
# @api public
|
|
112
|
+
def team_execution_result(team_execution_id)
|
|
113
|
+
assert_observation_thread!
|
|
114
|
+
execution = team_executions.load(team_execution_id)
|
|
115
|
+
{
|
|
116
|
+
team_execution_id: execution.team_execution_id, team_id: execution.team_id,
|
|
117
|
+
status: execution.status, phase: execution.phase,
|
|
118
|
+
result_ref: execution.result_ref, error_ref: execution.error_ref,
|
|
119
|
+
result: execution.result_ref && contents.fetch_json(execution.result_ref),
|
|
120
|
+
error: execution.error_ref && contents.fetch_json(execution.error_ref)
|
|
121
|
+
}.then { |value| Phronomy::Agent::Immutable.copy(value) }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Lists retained Team runs; no continuation or callback delivery occurs.
|
|
125
|
+
# @api public
|
|
126
|
+
def list_team_executions(team_id, after: nil, limit: 100)
|
|
127
|
+
assert_observation_thread!
|
|
128
|
+
team_executions.list(team_id, after: after, limit: limit)
|
|
129
|
+
end
|
|
130
|
+
|
|
48
131
|
# Initializes a Persistence backend from record-oriented storage
|
|
49
132
|
# repositories.
|
|
50
133
|
#
|
|
@@ -74,12 +157,15 @@ module Phronomy
|
|
|
74
157
|
# advertised.
|
|
75
158
|
#
|
|
76
159
|
# @api public
|
|
77
|
-
def initialize(contents:, agents:, journals:, executions:, workflow_states:)
|
|
160
|
+
def initialize(contents:, agents:, journals:, executions:, workflow_states:, handoff_states:, teams:, team_executions:)
|
|
78
161
|
@contents = contents
|
|
79
162
|
@agents = RepositoryFacades::Agents.new(agents)
|
|
80
163
|
@journals = RepositoryFacades::Journals.new(journals)
|
|
81
164
|
@executions = RepositoryFacades::Executions.new(executions)
|
|
82
165
|
@workflow_states = RepositoryFacades::WorkflowStates.new(workflow_states)
|
|
166
|
+
@handoff_states = RepositoryFacades::HandoffStates.new(handoff_states)
|
|
167
|
+
@teams = RepositoryFacades::Teams.new(teams)
|
|
168
|
+
@team_executions = RepositoryFacades::TeamExecutions.new(team_executions)
|
|
83
169
|
validate_capabilities!
|
|
84
170
|
end
|
|
85
171
|
|
|
@@ -141,6 +227,7 @@ module Phronomy
|
|
|
141
227
|
journals:,
|
|
142
228
|
executions:,
|
|
143
229
|
workflow_states:,
|
|
230
|
+
handoff_states:, teams:, team_executions:,
|
|
144
231
|
watermark:
|
|
145
232
|
)
|
|
146
233
|
RepositoryFacades::View.new(
|
|
@@ -149,6 +236,7 @@ module Phronomy
|
|
|
149
236
|
journals: journals,
|
|
150
237
|
executions: executions,
|
|
151
238
|
workflow_states: workflow_states,
|
|
239
|
+
handoff_states: handoff_states, teams: teams, team_executions: team_executions,
|
|
152
240
|
watermark: watermark
|
|
153
241
|
)
|
|
154
242
|
end
|
|
@@ -169,6 +257,12 @@ module Phronomy
|
|
|
169
257
|
|
|
170
258
|
private
|
|
171
259
|
|
|
260
|
+
def assert_observation_thread!
|
|
261
|
+
if Phronomy::Runtime.in_event_loop_context?
|
|
262
|
+
raise Phronomy::EventLoopReentrancyError, "Persistence observation cannot block EventLoop"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
172
266
|
def validate_capabilities!
|
|
173
267
|
missing = REQUIRED_CAPABILITIES.reject do |key, value|
|
|
174
268
|
capabilities[key] == value
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require "time"
|
|
5
|
+
|
|
6
|
+
RSpec.shared_context "coordination repository values" do
|
|
7
|
+
let(:coordination_team) do
|
|
8
|
+
now = Time.now.utc.iso8601(6)
|
|
9
|
+
Phronomy::MultiAgent::TeamRoot.new(team_id: SecureRandom.uuid,
|
|
10
|
+
team_definition_id: "contract-team", team_definition_version: 1,
|
|
11
|
+
team_revision: 0, lifecycle_status: "idle", created_at: now, updated_at: now, metadata: {})
|
|
12
|
+
end
|
|
13
|
+
let(:coordination_run) do
|
|
14
|
+
now = Time.now.utc.iso8601(6)
|
|
15
|
+
Phronomy::MultiAgent::TeamExecution.new(team_execution_id: SecureRandom.uuid,
|
|
16
|
+
team_id: coordination_team.team_id, execution_revision: 0, status: "active", phase: "coordinator",
|
|
17
|
+
input_ref: nil, coordinator: {}, tasks: [], workers: [], assignments: [], result_ref: nil,
|
|
18
|
+
error_ref: nil, created_at: now, updated_at: now, metadata: {})
|
|
19
|
+
end
|
|
20
|
+
let(:coordination_handoff) do
|
|
21
|
+
now = Time.now.utc.iso8601(6)
|
|
22
|
+
Phronomy::Agent::HandoffState.new(main_agent_id: SecureRandom.uuid, handoff_revision: 1,
|
|
23
|
+
active_agent_id: "contract-target", active_handoff_context_ref: nil, phase: "target_pending",
|
|
24
|
+
pending_source_execution_id: "source-execution", pending_target_execution_id: "target-execution",
|
|
25
|
+
created_at: now, updated_at: now, metadata: {})
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
RSpec.shared_examples "a Handoff state repository" do
|
|
30
|
+
include_context "coordination repository values"
|
|
31
|
+
|
|
32
|
+
it "returns nil only for an authoritative absent Handoff anchor" do
|
|
33
|
+
expect(persistence.handoff_states.load(SecureRandom.uuid)).to be_nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "round-trips the immutable Handoff snapshot and rejects stale routing CAS" do
|
|
37
|
+
value = coordination_handoff
|
|
38
|
+
persistence.handoff_states.save(value.main_agent_id, expected_revision: nil, state: value)
|
|
39
|
+
loaded = persistence.handoff_states.load(value.main_agent_id)
|
|
40
|
+
expect(loaded.to_h).to eq(value.to_h)
|
|
41
|
+
expect(loaded).to be_frozen
|
|
42
|
+
updated = value.with(phase: "stable")
|
|
43
|
+
persistence.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
|
|
44
|
+
expect do
|
|
45
|
+
persistence.handoff_states.save(value.main_agent_id, expected_revision: 1, state: updated)
|
|
46
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
47
|
+
expect(persistence.handoff_states.load(value.main_agent_id).handoff_revision).to eq(2)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "rejects a snapshot for a different routing anchor" do
|
|
51
|
+
expect do
|
|
52
|
+
persistence.handoff_states.save("other", expected_revision: nil, state: coordination_handoff)
|
|
53
|
+
end.to raise_error(Phronomy::Persistence::SerializationError)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
RSpec.shared_examples "a Team repository" do
|
|
58
|
+
include_context "coordination repository values"
|
|
59
|
+
|
|
60
|
+
it "round-trips a Team lineage and rejects duplicate creation" do
|
|
61
|
+
persistence.teams.create(coordination_team)
|
|
62
|
+
expect(persistence.teams.load(coordination_team.team_id).to_h).to eq(coordination_team.to_h)
|
|
63
|
+
expect { persistence.teams.create(coordination_team) }.to raise_error(Phronomy::Persistence::ConflictError)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "rejects a stale Team revision" do
|
|
67
|
+
persistence.teams.create(coordination_team)
|
|
68
|
+
updated = coordination_team.with(lifecycle_status: "active")
|
|
69
|
+
persistence.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
|
|
70
|
+
expect do
|
|
71
|
+
persistence.teams.save(coordination_team.team_id, expected_revision: 0, root: updated)
|
|
72
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "raises NotFoundError for an absent Team" do
|
|
76
|
+
expect { persistence.teams.load(SecureRandom.uuid) }.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
RSpec.shared_examples "a Team execution repository" do
|
|
81
|
+
include_context "coordination repository values"
|
|
82
|
+
before { persistence.teams.create(coordination_team) }
|
|
83
|
+
|
|
84
|
+
it "atomically admits at most one active run per Team" do
|
|
85
|
+
persistence.team_executions.create_active(coordination_run)
|
|
86
|
+
other = coordination_run.with(team_execution_id: SecureRandom.uuid, execution_revision: 0)
|
|
87
|
+
expect { persistence.team_executions.create_active(other) }.to raise_error(Phronomy::AgentBusyError)
|
|
88
|
+
expect(persistence.team_executions.list_active(coordination_team.team_id).map(&:team_execution_id)).to eq([coordination_run.team_execution_id])
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "releases admission after terminal CAS while retaining discoverable outcomes" do
|
|
92
|
+
persistence.team_executions.create_active(coordination_run)
|
|
93
|
+
completed = coordination_run.with(status: "completed", phase: "completed")
|
|
94
|
+
persistence.team_executions.save(coordination_run.team_execution_id, expected_revision: 0, execution: completed)
|
|
95
|
+
other = coordination_run.with(team_execution_id: SecureRandom.uuid, execution_revision: 0)
|
|
96
|
+
persistence.team_executions.create_active(other)
|
|
97
|
+
ids = [completed.team_execution_id, other.team_execution_id].sort
|
|
98
|
+
expect(persistence.team_executions.list(coordination_team.team_id, limit: 1).map(&:team_execution_id)).to eq(ids.first(1))
|
|
99
|
+
expect(persistence.team_executions.list(coordination_team.team_id, after: ids.first).map(&:team_execution_id)).to eq(ids.last(1))
|
|
100
|
+
expect(persistence.team_executions.list("other-team")).to be_empty
|
|
101
|
+
expect do
|
|
102
|
+
persistence.team_executions.save(completed.team_execution_id, expected_revision: 0, execution: completed)
|
|
103
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
104
|
+
expect do
|
|
105
|
+
persistence.team_executions.save(completed.team_execution_id, expected_revision: 1,
|
|
106
|
+
execution: completed.with(status: "active", phase: "coordinator"))
|
|
107
|
+
end.to raise_error(Phronomy::Persistence::ConflictError)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "rolls the new three repositories back with the existing transaction domain" do
|
|
111
|
+
handoff = coordination_handoff
|
|
112
|
+
root_id = "coordination-rollback-agent-#{SecureRandom.uuid}"
|
|
113
|
+
content_ref = nil
|
|
114
|
+
expect do
|
|
115
|
+
persistence.transaction do |tx|
|
|
116
|
+
tx.team_executions.create_active(coordination_run)
|
|
117
|
+
tx.teams.save(coordination_team.team_id, expected_revision: 0, root: coordination_team.with(lifecycle_status: "active"))
|
|
118
|
+
tx.handoff_states.save(handoff.main_agent_id, expected_revision: nil, state: handoff)
|
|
119
|
+
content_ref = tx.contents.put_text("coordination-rollback-#{SecureRandom.uuid}")
|
|
120
|
+
root = Phronomy::Agent::AgentRoot.create(agent_id: root_id, agent_definition_id: "rollback", agent_definition_version: 1)
|
|
121
|
+
tx.agents.create(root)
|
|
122
|
+
tx.journals.append(root_id, expected_position: 0, records: [])
|
|
123
|
+
record = Phronomy::Agent::JournalRecord.new(agent_id: root_id, kind: :input_received, channel: :external)
|
|
124
|
+
tx.executions.create_active(Phronomy::Agent::AgentExecution.start(agent_root: root, input_record: record))
|
|
125
|
+
tx.workflow_states.save(root_id, expected_revision: nil, snapshot: {fields: {value: "committed"}, phase: "pause"})
|
|
126
|
+
raise "rollback all eight"
|
|
127
|
+
end
|
|
128
|
+
end.to raise_error(RuntimeError, "rollback all eight")
|
|
129
|
+
expect(persistence.teams.load(coordination_team.team_id).team_revision).to eq(0)
|
|
130
|
+
expect(persistence.handoff_states.load(handoff.main_agent_id)).to be_nil
|
|
131
|
+
expect(persistence.team_executions.list(coordination_team.team_id)).to be_empty
|
|
132
|
+
expect { persistence.agents.load(root_id) }.to raise_error(Phronomy::Persistence::NotFoundError)
|
|
133
|
+
expect(persistence.executions.list(root_id)).to be_empty
|
|
134
|
+
expect(persistence.workflow_states.load(root_id)).to be_nil
|
|
135
|
+
expect(persistence.contents.exist?(content_ref)).to be(false)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -27,6 +27,9 @@ module Phronomy
|
|
|
27
27
|
"a Journal repository",
|
|
28
28
|
"an Execution repository",
|
|
29
29
|
"a workflow state repository",
|
|
30
|
+
"a Handoff state repository",
|
|
31
|
+
"a Team repository",
|
|
32
|
+
"a Team execution repository",
|
|
30
33
|
"a Persistence backend"
|
|
31
34
|
].freeze
|
|
32
35
|
end
|
|
@@ -39,3 +42,5 @@ require_relative "persistence_contract/a_journal_repository"
|
|
|
39
42
|
require_relative "persistence_contract/an_execution_repository"
|
|
40
43
|
require_relative "persistence_contract/a_workflow_state_repository"
|
|
41
44
|
require_relative "persistence_contract/a_persistence_backend"
|
|
45
|
+
|
|
46
|
+
require_relative "persistence_contract/coordination_repositories"
|
data/lib/phronomy/tools/agent.rb
CHANGED
|
@@ -161,7 +161,7 @@ module Phronomy
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def settle_async_error(task, error)
|
|
164
|
-
if error.is_a?(Phronomy::ToolError) || error.is_a?(Phronomy::CancellationError)
|
|
164
|
+
if error.is_a?(Phronomy::ToolError) || error.is_a?(Phronomy::CancellationError) || error.is_a?(Phronomy::ExecutionRehydrationRequiredError)
|
|
165
165
|
task.fail(error)
|
|
166
166
|
return task
|
|
167
167
|
end
|
data/lib/phronomy/version.rb
CHANGED
data/scripts/api_snapshot.rb
CHANGED
|
@@ -34,9 +34,9 @@ PUBLIC_API_ENTRIES = [
|
|
|
34
34
|
Phronomy::Runnable,
|
|
35
35
|
Phronomy::Agent::Context::Instruction::PromptTemplate,
|
|
36
36
|
# Beta
|
|
37
|
-
Phronomy::
|
|
38
|
-
Phronomy::
|
|
39
|
-
Phronomy::
|
|
37
|
+
Phronomy::Agent::Handoff,
|
|
38
|
+
Phronomy::Agent::HandoffPolicy,
|
|
39
|
+
Phronomy::Agent::HandoffRunner,
|
|
40
40
|
Phronomy::MultiAgent::Orchestrator,
|
|
41
41
|
Phronomy::MultiAgent::TeamCoordinator,
|
|
42
42
|
Phronomy::Filter::Base,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Phronomy
|
|
2
|
+
module Agent
|
|
3
|
+
class Handoff
|
|
4
|
+
attr_reader source_agent: ::Phronomy::Agent::Base
|
|
5
|
+
attr_reader target_agent: ::Phronomy::Agent::Base
|
|
6
|
+
attr_reader policy: HandoffPolicy
|
|
7
|
+
attr_reader description: String
|
|
8
|
+
|
|
9
|
+
def initialize: (source_agent: ::Phronomy::Agent::Base, target_agent: ::Phronomy::Agent::Base, ?policy: HandoffPolicy, ?description: String?) -> void
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class HandoffPolicy
|
|
13
|
+
CATEGORIES: Array[Symbol]
|
|
14
|
+
MODES: Array[Symbol]
|
|
15
|
+
DEFAULTS: Array[Symbol]
|
|
16
|
+
|
|
17
|
+
def self.define: () { () -> void } -> HandoffPolicy
|
|
18
|
+
def self.default: () -> HandoffPolicy
|
|
19
|
+
|
|
20
|
+
def rule: (Symbol | String) -> untyped
|
|
21
|
+
def required?: (Symbol | String) -> bool
|
|
22
|
+
def forbidden?: (Symbol | String) -> bool
|
|
23
|
+
def selectable?: (Symbol | String) -> bool
|
|
24
|
+
def default_include?: (Symbol | String) -> bool
|
|
25
|
+
def selectable_categories: () -> Array[Symbol]
|
|
26
|
+
def to_h: () -> Hash[String, Hash[String, String]]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class HandoffRunner
|
|
30
|
+
MAX_HANDOFFS: Integer
|
|
31
|
+
|
|
32
|
+
attr_reader main_agent: ::Phronomy::Agent::Base
|
|
33
|
+
attr_reader handoffs: Array[Handoff]
|
|
34
|
+
|
|
35
|
+
def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[Handoff]) -> void
|
|
36
|
+
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
37
|
+
def result: (String execution_id) -> Hash[Symbol, untyped]
|
|
38
|
+
def cancel: (String execution_id) -> Hash[Symbol, untyped]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
module Phronomy
|
|
2
2
|
module MultiAgent
|
|
3
|
-
class
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def
|
|
3
|
+
class Orchestrator < ::Phronomy::Agent::Base
|
|
4
|
+
def self.subagent: (Symbol | String name, singleton(::Phronomy::Agent::Base) agent_class, ?on_error: Symbol, ?inherit_knowledge: bool) -> untyped
|
|
5
|
+
def self.registered_subagents: () -> Hash[Symbol | String, untyped]
|
|
6
|
+
def resume: (String execution_id, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
7
|
+
def dispatch_parallel: (*Hash[Symbol, untyped] tasks, ?max_concurrency: Integer?, ?on_error: Symbol, ?timeout: Numeric?, ?cancellation_token: untyped, ?invocation_context: untyped, ?inherit_knowledge: bool) -> Array[untyped]
|
|
8
|
+
def dispatch_parallel_async: (*Hash[Symbol, untyped] tasks, ?max_concurrency: Integer?, ?on_error: Symbol, ?timeout: Numeric?, ?cancellation_token: untyped, ?invocation_context: untyped, ?inherit_knowledge: bool) -> ::Phronomy::Task[untyped]
|
|
9
|
+
def fan_out: (agent: singleton(::Phronomy::Agent::Base), inputs: Array[untyped], ?config: Hash[Symbol, untyped], ?max_concurrency: Integer?, ?on_error: Symbol, ?timeout: Numeric?, ?cancellation_token: untyped, ?invocation_context: untyped, ?inherit_knowledge: bool) -> Array[untyped]
|
|
10
|
+
def fan_out_async: (agent: singleton(::Phronomy::Agent::Base), inputs: Array[untyped], ?config: Hash[Symbol, untyped], ?max_concurrency: Integer?, ?on_error: Symbol, ?timeout: Numeric?, ?cancellation_token: untyped, ?invocation_context: untyped, ?inherit_knowledge: bool) -> ::Phronomy::Task[untyped]
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
class
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def self.
|
|
18
|
-
def self.
|
|
19
|
-
|
|
20
|
-
def
|
|
21
|
-
def
|
|
22
|
-
def
|
|
23
|
-
def
|
|
24
|
-
def
|
|
25
|
-
def
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
attr_reader main_agent: ::Phronomy::Agent::Base
|
|
33
|
-
attr_reader handoffs: Array[Handoff]
|
|
34
|
-
|
|
35
|
-
def initialize: (main_agent: ::Phronomy::Agent::Base, ?handoffs: Array[Handoff]) -> void
|
|
36
|
-
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
13
|
+
class TeamCoordinator
|
|
14
|
+
attr_reader team_id: String
|
|
15
|
+
attr_reader persistence: ::Phronomy::Persistence
|
|
16
|
+
def self.team_definition: (?id: String?, ?version: Integer?) -> Hash[Symbol, String | Integer]
|
|
17
|
+
def self.coordinator_model: (?String? value) -> String?
|
|
18
|
+
def self.coordinator_instructions: (?String? value) -> String?
|
|
19
|
+
def self.coordinator_provider: (?Symbol? value) -> Symbol?
|
|
20
|
+
def self.pool: (size: Integer, agent: singleton(::Phronomy::Agent::Base), ?on_error: Symbol) -> untyped
|
|
21
|
+
def self.schedule: () { (Array[untyped]) -> untyped } -> untyped
|
|
22
|
+
def self.aggregate: () { (Array[Hash[Symbol, untyped]]) -> untyped } -> untyped
|
|
23
|
+
def self.new: (?team_id: String, ?persistence: ::Phronomy::Persistence?, ?metadata: Hash[String, untyped], ?on_event: ^(untyped) -> untyped) -> instance
|
|
24
|
+
def self.create: (**untyped options) -> instance
|
|
25
|
+
def self.load: (String team_id, persistence: ::Phronomy::Persistence, ?on_event: ^(untyped) -> untyped) -> instance
|
|
26
|
+
def self.get: (String team_id) -> instance?
|
|
27
|
+
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> untyped
|
|
28
|
+
def stream: (untyped input, ?config: Hash[Symbol, untyped]) ?{ (Hash[Symbol, untyped]) -> untyped } -> untyped
|
|
29
|
+
def resume: (String team_execution_id, ?config: Hash[Symbol, untyped]) -> untyped
|
|
30
|
+
def result: (String team_execution_id) -> Hash[Symbol, untyped]
|
|
31
|
+
def executions: (?after: String?, ?limit: Integer) -> Array[untyped]
|
|
32
|
+
def cancel: (String team_execution_id) -> Hash[Symbol, untyped]
|
|
37
33
|
end
|
|
38
34
|
end
|
|
39
35
|
end
|
|
@@ -25,6 +25,7 @@ module Phronomy
|
|
|
25
25
|
def load: (String execution_id) -> untyped
|
|
26
26
|
def save: (String execution_id, expected_revision: Integer, execution: untyped) -> untyped
|
|
27
27
|
def list_active: (String agent_id) -> Array[untyped]
|
|
28
|
+
def list: (String agent_id, ?after: String?, ?limit: Integer) -> Array[untyped]
|
|
28
29
|
def delete: (String execution_id) -> untyped
|
|
29
30
|
def delete_for_agent: (String agent_id) -> untyped
|
|
30
31
|
def assert_idle!: (String agent_id) -> untyped
|
|
@@ -58,6 +59,7 @@ module Phronomy
|
|
|
58
59
|
def load: (String execution_id) -> Persistence::DurableRecord
|
|
59
60
|
def save: (String execution_id, expected_revision: Integer, next_revision: Integer, agent_id: String, active: bool, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
60
61
|
def list_active: (String agent_id) -> Array[Persistence::DurableRecord]
|
|
62
|
+
def list: (String agent_id, ?after: String?, ?limit: Integer) -> Array[Persistence::DurableRecord]
|
|
61
63
|
def delete: (String execution_id) -> untyped
|
|
62
64
|
def delete_for_agent: (String agent_id) -> untyped
|
|
63
65
|
def assert_idle!: (String agent_id) -> untyped
|
|
@@ -69,6 +71,54 @@ module Phronomy
|
|
|
69
71
|
def delete: (String workflow_instance_id, expected_revision: Integer) -> untyped
|
|
70
72
|
end
|
|
71
73
|
|
|
74
|
+
interface _HandoffStateRepository
|
|
75
|
+
def load: (String main_agent_id) -> untyped
|
|
76
|
+
def save: (String main_agent_id, expected_revision: Integer?, state: untyped) -> untyped
|
|
77
|
+
def delete: (String main_agent_id, expected_revision: Integer) -> untyped
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
interface _TeamRepository
|
|
81
|
+
def create: (untyped root) -> untyped
|
|
82
|
+
def load: (String team_id) -> untyped
|
|
83
|
+
def save: (String team_id, expected_revision: Integer, root: untyped) -> untyped
|
|
84
|
+
def delete: (String team_id) -> untyped
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
interface _TeamExecutionRepository
|
|
88
|
+
def create_active: (untyped execution) -> untyped
|
|
89
|
+
def load: (String team_execution_id) -> untyped
|
|
90
|
+
def save: (String team_execution_id, expected_revision: Integer, execution: untyped) -> untyped
|
|
91
|
+
def list_active: (String team_id) -> Array[untyped]
|
|
92
|
+
def list: (String team_id, ?after: String?, ?limit: Integer) -> Array[untyped]
|
|
93
|
+
def delete: (String team_execution_id) -> untyped
|
|
94
|
+
def delete_for_team: (String team_id) -> untyped
|
|
95
|
+
def assert_idle!: (String team_id) -> untyped
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
interface _BackendHandoffStateRecordRepository
|
|
99
|
+
def load: (String main_agent_id) -> Persistence::DurableRecord?
|
|
100
|
+
def save: (String main_agent_id, expected_revision: Integer?, next_revision: Integer, active_agent_id: String, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
101
|
+
def delete: (String main_agent_id, expected_revision: Integer) -> untyped
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
interface _BackendTeamRecordRepository
|
|
105
|
+
def create: (team_id: String, team_revision: Integer, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
106
|
+
def load: (String team_id) -> Persistence::DurableRecord
|
|
107
|
+
def save: (String team_id, expected_revision: Integer, next_revision: Integer, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
108
|
+
def delete: (String team_id) -> untyped
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
interface _BackendTeamExecutionRecordRepository
|
|
112
|
+
def create_active: (team_execution_id: String, team_id: String, execution_revision: Integer, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
113
|
+
def load: (String team_execution_id) -> Persistence::DurableRecord
|
|
114
|
+
def save: (String team_execution_id, expected_revision: Integer, next_revision: Integer, team_id: String, active: bool, record: Persistence::DurableRecord) -> Persistence::DurableRecord
|
|
115
|
+
def list_active: (String team_id) -> Array[Persistence::DurableRecord]
|
|
116
|
+
def list: (String team_id, ?after: String?, ?limit: Integer) -> Array[Persistence::DurableRecord]
|
|
117
|
+
def delete: (String team_execution_id) -> untyped
|
|
118
|
+
def delete_for_team: (String team_id) -> untyped
|
|
119
|
+
def assert_idle!: (String team_id) -> untyped
|
|
120
|
+
end
|
|
121
|
+
|
|
72
122
|
interface _BackendWatermark
|
|
73
123
|
def assert_agent_watermark!: (agent_id: String, agent_revision: Integer, journal_position: Integer) -> true
|
|
74
124
|
end
|
|
@@ -79,6 +129,9 @@ module Phronomy
|
|
|
79
129
|
def journals: () -> _JournalRepository
|
|
80
130
|
def executions: () -> _ExecutionRepository
|
|
81
131
|
def workflow_states: () -> _WorkflowStateRepository
|
|
132
|
+
def handoff_states: () -> _HandoffStateRepository
|
|
133
|
+
def teams: () -> _TeamRepository
|
|
134
|
+
def team_executions: () -> _TeamExecutionRepository
|
|
82
135
|
def assert_agent_watermark!: (agent_id: String, agent_revision: Integer, journal_position: Integer) -> true
|
|
83
136
|
end
|
|
84
137
|
|
|
@@ -118,11 +171,19 @@ module Phronomy
|
|
|
118
171
|
attr_reader journals: _JournalRepository
|
|
119
172
|
attr_reader executions: _ExecutionRepository
|
|
120
173
|
attr_reader workflow_states: _WorkflowStateRepository
|
|
121
|
-
|
|
122
|
-
|
|
174
|
+
attr_reader handoff_states: _HandoffStateRepository
|
|
175
|
+
attr_reader teams: _TeamRepository
|
|
176
|
+
attr_reader team_executions: _TeamExecutionRepository
|
|
177
|
+
def handoff_result: (String execution_id, ?main_agent_id: String?) -> Hash[Symbol, untyped]
|
|
178
|
+
def execution_result: (String execution_id) -> Hash[Symbol, untyped]
|
|
179
|
+
def list_executions: (String agent_id, ?after: String?, ?limit: Integer) -> Array[untyped]
|
|
180
|
+
def team_execution_result: (String team_execution_id) -> Hash[Symbol, untyped]
|
|
181
|
+
def list_team_executions: (String team_id, ?after: String?, ?limit: Integer) -> Array[untyped]
|
|
182
|
+
|
|
183
|
+
def initialize: (contents: _ContentRepository, agents: _BackendAgentRecordRepository, journals: _BackendJournalRecordRepository, executions: _BackendExecutionRecordRepository, workflow_states: _BackendWorkflowStateRecordRepository, handoff_states: _BackendHandoffStateRecordRepository, teams: _BackendTeamRecordRepository, team_executions: _BackendTeamExecutionRecordRepository) -> void
|
|
123
184
|
def capabilities: () -> Hash[Symbol, bool]
|
|
124
185
|
def transaction: () { (_PersistenceTransactionView) -> untyped } -> untyped
|
|
125
|
-
def build_transaction_view: (contents: _ContentRepository, agents: _BackendAgentRecordRepository, journals: _BackendJournalRecordRepository, executions: _BackendExecutionRecordRepository, workflow_states: _BackendWorkflowStateRecordRepository, watermark: _BackendWatermark) -> _PersistenceTransactionView
|
|
186
|
+
def build_transaction_view: (contents: _ContentRepository, agents: _BackendAgentRecordRepository, journals: _BackendJournalRecordRepository, executions: _BackendExecutionRecordRepository, workflow_states: _BackendWorkflowStateRecordRepository, handoff_states: _BackendHandoffStateRecordRepository, teams: _BackendTeamRecordRepository, team_executions: _BackendTeamExecutionRecordRepository, watermark: _BackendWatermark) -> _PersistenceTransactionView
|
|
126
187
|
def assert_agent_watermark!: (agent_id: String, agent_revision: Integer, journal_position: Integer) -> true
|
|
127
188
|
end
|
|
128
189
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: phronomy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.24.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Raizo T.C.S
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -150,7 +150,17 @@ files:
|
|
|
150
150
|
- docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md
|
|
151
151
|
- docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md
|
|
152
152
|
- docs/decisions/027-llm-adapter-provider-boundary.md
|
|
153
|
+
- docs/decisions/028-preparing-recovery-replay-contract.md
|
|
154
|
+
- docs/decisions/029-semantic-completion-and-application-effect-boundary.md
|
|
155
|
+
- docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md
|
|
156
|
+
- docs/decisions/031-durable-multi-agent-coordination.md
|
|
153
157
|
- docs/decisions/README.md
|
|
158
|
+
- docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md
|
|
159
|
+
- docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md
|
|
160
|
+
- docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md
|
|
161
|
+
- docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md
|
|
162
|
+
- docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md
|
|
163
|
+
- docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md
|
|
154
164
|
- docs/features.md
|
|
155
165
|
- docs/getting-started.md
|
|
156
166
|
- docs/mcp-client.md
|
|
@@ -158,6 +168,7 @@ files:
|
|
|
158
168
|
- docs/migrations/0.16.md
|
|
159
169
|
- docs/migrations/0.19.md
|
|
160
170
|
- docs/migrations/0.22.md
|
|
171
|
+
- docs/migrations/durable-semantic-coordination-v2.md
|
|
161
172
|
- docs/persistence-backends.md
|
|
162
173
|
- docs/runtime-and-concurrency.md
|
|
163
174
|
- examples/README.md
|
|
@@ -186,7 +197,18 @@ files:
|
|
|
186
197
|
- lib/phronomy/agent/context_policy.rb
|
|
187
198
|
- lib/phronomy/agent/context_policy_input.rb
|
|
188
199
|
- lib/phronomy/agent/context_policy_input_builder.rb
|
|
200
|
+
- lib/phronomy/agent/exact_execution.rb
|
|
201
|
+
- lib/phronomy/agent/execution_cancellation.rb
|
|
189
202
|
- lib/phronomy/agent/execution_coordinator.rb
|
|
203
|
+
- lib/phronomy/agent/handoff.rb
|
|
204
|
+
- lib/phronomy/agent/handoff_capability_factory.rb
|
|
205
|
+
- lib/phronomy/agent/handoff_context.rb
|
|
206
|
+
- lib/phronomy/agent/handoff_execution_coordinator.rb
|
|
207
|
+
- lib/phronomy/agent/handoff_policy.rb
|
|
208
|
+
- lib/phronomy/agent/handoff_projection.rb
|
|
209
|
+
- lib/phronomy/agent/handoff_request.rb
|
|
210
|
+
- lib/phronomy/agent/handoff_runner.rb
|
|
211
|
+
- lib/phronomy/agent/handoff_state.rb
|
|
190
212
|
- lib/phronomy/agent/immutable.rb
|
|
191
213
|
- lib/phronomy/agent/journal_projection.rb
|
|
192
214
|
- lib/phronomy/agent/journal_record.rb
|
|
@@ -233,6 +255,7 @@ files:
|
|
|
233
255
|
- lib/phronomy/engine/runtime.rb
|
|
234
256
|
- lib/phronomy/engine/runtime/agent_ownership_registry.rb
|
|
235
257
|
- lib/phronomy/engine/runtime/shutdown_result.rb
|
|
258
|
+
- lib/phronomy/engine/runtime/team_ownership_registry.rb
|
|
236
259
|
- lib/phronomy/engine/runtime/timer_queue.rb
|
|
237
260
|
- lib/phronomy/engine/runtime/timer_service.rb
|
|
238
261
|
- lib/phronomy/engine/task.rb
|
|
@@ -254,21 +277,14 @@ files:
|
|
|
254
277
|
- lib/phronomy/llm_context_window/token_estimator.rb
|
|
255
278
|
- lib/phronomy/metrics.rb
|
|
256
279
|
- lib/phronomy/multi_agent/admission_registry.rb
|
|
257
|
-
- lib/phronomy/multi_agent/
|
|
258
|
-
- lib/phronomy/multi_agent/coordinator.rb
|
|
259
|
-
- lib/phronomy/multi_agent/execution_coordinator.rb
|
|
280
|
+
- lib/phronomy/multi_agent/durable_subagent_coordinator.rb
|
|
260
281
|
- lib/phronomy/multi_agent/fan_out_invocation.rb
|
|
261
282
|
- lib/phronomy/multi_agent/fan_out_session_builder.rb
|
|
262
|
-
- lib/phronomy/multi_agent/handoff.rb
|
|
263
|
-
- lib/phronomy/multi_agent/handoff_capability_factory.rb
|
|
264
|
-
- lib/phronomy/multi_agent/handoff_context.rb
|
|
265
|
-
- lib/phronomy/multi_agent/handoff_policy.rb
|
|
266
|
-
- lib/phronomy/multi_agent/handoff_projection.rb
|
|
267
|
-
- lib/phronomy/multi_agent/handoff_request.rb
|
|
268
283
|
- lib/phronomy/multi_agent/orchestrator.rb
|
|
269
284
|
- lib/phronomy/multi_agent/parallel_tool_chat.rb
|
|
270
|
-
- lib/phronomy/multi_agent/runner.rb
|
|
271
285
|
- lib/phronomy/multi_agent/team_coordinator.rb
|
|
286
|
+
- lib/phronomy/multi_agent/team_execution.rb
|
|
287
|
+
- lib/phronomy/multi_agent/team_root.rb
|
|
272
288
|
- lib/phronomy/output_parser.rb
|
|
273
289
|
- lib/phronomy/output_parser/base.rb
|
|
274
290
|
- lib/phronomy/output_parser/json_parser.rb
|
|
@@ -304,6 +320,7 @@ files:
|
|
|
304
320
|
- lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb
|
|
305
321
|
- lib/phronomy/testing/persistence_contract/an_agent_repository.rb
|
|
306
322
|
- lib/phronomy/testing/persistence_contract/an_execution_repository.rb
|
|
323
|
+
- lib/phronomy/testing/persistence_contract/coordination_repositories.rb
|
|
307
324
|
- lib/phronomy/token_usage.rb
|
|
308
325
|
- lib/phronomy/tool.rb
|
|
309
326
|
- lib/phronomy/tool/base.rb
|
|
@@ -350,6 +367,7 @@ files:
|
|
|
350
367
|
- sig/phronomy.rbs
|
|
351
368
|
- sig/phronomy/agent.rbs
|
|
352
369
|
- sig/phronomy/extensions.rbs
|
|
370
|
+
- sig/phronomy/handoff.rbs
|
|
353
371
|
- sig/phronomy/llm_adapter.rbs
|
|
354
372
|
- sig/phronomy/multi_agent.rbs
|
|
355
373
|
- sig/phronomy/persistence.rbs
|