phronomy 0.22.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 +3 -4
- data/CHANGELOG.md +215 -10
- data/CONTRIBUTING.md +81 -9
- data/README.md +15 -6
- 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 +147 -0
- data/docs/architecture/persistence.md +186 -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 +89 -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 +114 -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/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 +176 -0
- 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 +65 -11
- data/docs/getting-started.md +77 -45
- data/docs/migrations/0.19.md +14 -7
- data/docs/migrations/0.22.md +390 -0
- data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
- data/docs/persistence-backends.md +129 -40
- data/docs/runtime-and-concurrency.md +227 -33
- data/examples/README.md +13 -0
- data/lib/phronomy/agent/agent_execution.rb +21 -17
- 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 +162 -72
- data/lib/phronomy/agent/base.rb +416 -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/exact_execution.rb +153 -0
- data/lib/phronomy/agent/execution_cancellation.rb +25 -0
- data/lib/phronomy/agent/execution_coordinator.rb +2417 -572
- data/lib/phronomy/agent/handoff.rb +43 -0
- data/lib/phronomy/agent/handoff_capability_factory.rb +45 -0
- data/lib/phronomy/agent/handoff_context.rb +120 -0
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +143 -0
- data/lib/phronomy/agent/handoff_policy.rb +143 -0
- data/lib/phronomy/agent/handoff_projection.rb +207 -0
- data/lib/phronomy/agent/handoff_request.rb +45 -0
- data/lib/phronomy/agent/handoff_runner.rb +178 -0
- data/lib/phronomy/agent/handoff_state.rb +43 -0
- 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 +174 -0
- data/lib/phronomy/agent/recovery_coordinator/installation.rb +381 -0
- data/lib/phronomy/agent/recovery_coordinator/resolution.rb +511 -0
- data/lib/phronomy/agent/recovery_coordinator.rb +217 -0
- data/lib/phronomy/agent/recovery_support.rb +504 -0
- data/lib/phronomy/agent/ruby_llm_materializer.rb +16 -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 +339 -103
- 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/team_ownership_registry.rb +77 -0
- data/lib/phronomy/engine/runtime.rb +92 -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/durable_subagent_coordinator.rb +134 -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/orchestrator.rb +71 -26
- 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 +706 -0
- data/lib/phronomy/persistence/durable_record.rb +117 -0
- data/lib/phronomy/persistence/in_memory.rb +471 -133
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
- data/lib/phronomy/persistence/repository_facades.rb +535 -0
- data/lib/phronomy/persistence.rb +174 -40
- 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 +2 -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/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/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/handoff.rbs +41 -0
- data/sig/phronomy/multi_agent.rbs +35 -0
- data/sig/phronomy/persistence.rbs +123 -4
- data/sig/phronomy/runtime.rbs +1 -4
- data/sig/phronomy/workflow.rbs +2 -2
- data/sig/phronomy.rbs +10 -0
- metadata +84 -18
- data/examples/workflows/agent_event_mapping.rb +0 -101
- 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
- data/lib/phronomy/multi_agent/handoff.rb +0 -64
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# Migration to 0.22
|
|
2
|
+
|
|
3
|
+
Phronomy 0.22 includes clean-break Agent definition identity normalization and
|
|
4
|
+
semantic Multi-Agent Handoff changes.
|
|
5
|
+
|
|
6
|
+
## Agent definition identity and revision
|
|
7
|
+
|
|
8
|
+
Agent instance identity and Agent definition identity are separate:
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
Agent instance agent_id
|
|
12
|
+
Agent definition lineage agent_definition_id
|
|
13
|
+
Agent definition revision agent_definition_version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
A named concrete Agent may now use its fully-qualified Ruby class name as the
|
|
17
|
+
default definition lineage:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
module Billing
|
|
21
|
+
class Agent < Phronomy::Agent::Base
|
|
22
|
+
agent_definition version: 2
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The definition ID above is `Billing::Agent`. An explicit stable lineage remains
|
|
28
|
+
supported:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
agent_definition id: "billing-agent", version: 2
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Concrete subclasses do not implicitly inherit a parent's definition revision.
|
|
35
|
+
Anonymous Agent subclasses cannot derive a fully-qualified class-name lineage
|
|
36
|
+
and therefore require explicit `id:` when declaring their definition identity.
|
|
37
|
+
|
|
38
|
+
The semantic revision field is a clean rename:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
AgentRoot#definition_version
|
|
42
|
+
-> AgentRoot#agent_definition_version
|
|
43
|
+
|
|
44
|
+
AgentRoot durable key "definition_version"
|
|
45
|
+
-> "agent_definition_version"
|
|
46
|
+
|
|
47
|
+
LLMInputBuildContext#definition_version
|
|
48
|
+
-> #agent_definition_version
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
No deprecated field alias or legacy AgentRoot backward decoder is provided.
|
|
52
|
+
Persisted AgentRoot hashes that contain only `"definition_version"` must be
|
|
53
|
+
migrated by the application before they are loaded by 0.22. Phronomy does not
|
|
54
|
+
rewrite existing AgentRoot data automatically in this change.
|
|
55
|
+
|
|
56
|
+
Existing `agent_id` values keep their identity semantics. Agent loading still
|
|
57
|
+
uses the current exact-match policy for `(agent_definition_id,
|
|
58
|
+
agent_definition_version)`. This semantic definition revision is not a
|
|
59
|
+
Persistence codec/schema/format version.
|
|
60
|
+
|
|
61
|
+
## Multi-Agent Handoff
|
|
62
|
+
|
|
63
|
+
Multi-Agent Handoff changes from Tool-result/sentinel routing to an explicit
|
|
64
|
+
framework control-transfer model. This is also a clean break: compatibility
|
|
65
|
+
aliases for the removed Runner and Handoff routing API are intentionally not
|
|
66
|
+
provided.
|
|
67
|
+
|
|
68
|
+
## Runner API
|
|
69
|
+
|
|
70
|
+
Before:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
runner = Phronomy::Agent::Runner.new(
|
|
74
|
+
agents: [triage, billing],
|
|
75
|
+
routes: {triage => [billing]}
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
After:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
handoff = Phronomy::MultiAgent::Handoff.new(
|
|
83
|
+
source_agent: triage,
|
|
84
|
+
target_agent: billing
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
runner = Phronomy::MultiAgent::Runner.new(
|
|
88
|
+
main_agent: triage,
|
|
89
|
+
handoffs: [handoff]
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Removed public surface:
|
|
94
|
+
|
|
95
|
+
- `Phronomy::Agent::Runner`
|
|
96
|
+
- Runner constructor keywords `agents:` and `routes:`
|
|
97
|
+
- Runner `#agents`
|
|
98
|
+
- sentinel-based routing internals as a public compatibility boundary
|
|
99
|
+
|
|
100
|
+
## Handoff model
|
|
101
|
+
|
|
102
|
+
`Phronomy::MultiAgent::Handoff` now represents one semantic Source-to-Target
|
|
103
|
+
edge between concrete live Agent instances:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
handoff = Phronomy::MultiAgent::Handoff.new(
|
|
107
|
+
source_agent: triage,
|
|
108
|
+
target_agent: billing,
|
|
109
|
+
description: "Transfer billing responsibility"
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Generated Tool names are transport details only. Applications must not persist,
|
|
114
|
+
inspect, or route by those generated names. `Handoff#tool_name`,
|
|
115
|
+
`Handoff#sentinel`, and `Handoff#to_tool_class` are not part of the new API.
|
|
116
|
+
|
|
117
|
+
A Handoff request contains a required `responsibility` string. It is intercepted
|
|
118
|
+
before ordinary Tool execution, so no synthetic Tool result is inserted merely
|
|
119
|
+
to signal routing.
|
|
120
|
+
|
|
121
|
+
One Provider outcome may contain either ordinary Tool Calls or one Handoff
|
|
122
|
+
request. Mixing Handoff with ordinary Tool Calls, or returning multiple Handoff
|
|
123
|
+
requests in one Provider outcome, raises `Phronomy::HandoffError`.
|
|
124
|
+
|
|
125
|
+
## Handoff Policy and Context transfer
|
|
126
|
+
|
|
127
|
+
`Phronomy::MultiAgent::HandoffPolicy` controls what may cross the Agent ownership
|
|
128
|
+
boundary. The initial categories are:
|
|
129
|
+
|
|
130
|
+
- `current_request`
|
|
131
|
+
- `history`
|
|
132
|
+
- `knowledge`
|
|
133
|
+
- `tool_exchanges`
|
|
134
|
+
|
|
135
|
+
Each category is `required`, `forbidden`, or `selectable`. Selectable categories
|
|
136
|
+
have an Application-defined default of include or exclude. Required and forbidden
|
|
137
|
+
categories are not exposed to the Source Agent as switches.
|
|
138
|
+
|
|
139
|
+
The default policy requires the current request, includes history and Tool
|
|
140
|
+
exchanges by default, and keeps persistent Knowledge opt-in.
|
|
141
|
+
|
|
142
|
+
Transferred material is immutable request-scoped Handoff Context. It is not
|
|
143
|
+
adopted automatically into the Target Journal or Target Knowledge. Provenance is
|
|
144
|
+
preserved across multi-hop transfers.
|
|
145
|
+
|
|
146
|
+
Handoff Policy and Context Policy have different authority:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
Handoff Policy
|
|
150
|
+
-> decides what may cross Source -> Target
|
|
151
|
+
|
|
152
|
+
Target Context Policy
|
|
153
|
+
-> decides what is used for one Target LLM call
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Transferred items therefore enter Target context assembly as ordinary selectable
|
|
157
|
+
Context candidates before Target Context Policy runs.
|
|
158
|
+
|
|
159
|
+
## Active Agent continuity
|
|
160
|
+
|
|
161
|
+
The `main_agent` instance anchors one Runtime-local coordination lifetime. After
|
|
162
|
+
a successful Handoff, the Target remains active for later user turns while the
|
|
163
|
+
same main Agent instance and Runtime remain alive. Recreating only the
|
|
164
|
+
`MultiAgent::Runner` facade does not reset that state.
|
|
165
|
+
|
|
166
|
+
This active-Agent ownership is deliberately not durable. A process or Runtime
|
|
167
|
+
reset starts a new coordination lifetime at `main_agent`; Phronomy does not infer
|
|
168
|
+
active-Agent continuation from historical Handoff audit records.
|
|
169
|
+
|
|
170
|
+
## Source execution outcome
|
|
171
|
+
|
|
172
|
+
A Source Agent execution that transfers responsibility terminates explicitly as
|
|
173
|
+
`handed_off`. The complete Provider outcome is retained for audit, but the
|
|
174
|
+
Handoff control Tool Call is not made a future conversational Context candidate
|
|
175
|
+
and no ordinary Handoff Tool result is generated.
|
|
176
|
+
|
|
177
|
+
## Context Policy clean break (ACS-04)
|
|
178
|
+
|
|
179
|
+
ACS-04 replaces the intermediate Context selection composition API with the
|
|
180
|
+
final four-category Context Policy SPI. Application-defined policies receive an
|
|
181
|
+
immutable `Phronomy::Agent::ContextPolicyInput` and return an immutable
|
|
182
|
+
`Phronomy::Agent::ContextPlan`, each organized as `instruction`, `knowledge`,
|
|
183
|
+
`tools`, and grouped `conversation`.
|
|
184
|
+
|
|
185
|
+
Agent classes bind one Application-constructed Policy instance:
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
class ResearchAgent < Phronomy::Agent::Base
|
|
189
|
+
context_policy RESEARCH_CONTEXT_POLICY
|
|
190
|
+
end
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The following intermediate APIs/internals are removed without compatibility
|
|
194
|
+
aliases:
|
|
195
|
+
|
|
196
|
+
- `ContextRequest`
|
|
197
|
+
- `ContextPolicyDescriptor` / `ContextPolicyRegistry`
|
|
198
|
+
- `DerivedContentSpec` and `ContextPlan#derived_contents`
|
|
199
|
+
- `ContextPlan#selected_unit_ids`, `#ordering_hints`, `#policy_descriptor`
|
|
200
|
+
- `Selection::Unit` / `Selection::Validator`
|
|
201
|
+
- `DependencyAwareUnitBuilder`
|
|
202
|
+
- `RequiredContextResolver`
|
|
203
|
+
- `RecentFirstSelector`
|
|
204
|
+
- `TokenBudgetPacker`
|
|
205
|
+
- public Policy `parts` composition
|
|
206
|
+
|
|
207
|
+
`Selection::Candidate` and `Selection::Constraint` remain internal normalization
|
|
208
|
+
mechanisms while `ContextPolicyInput` is built; they are not the Application
|
|
209
|
+
Policy SPI.
|
|
210
|
+
|
|
211
|
+
ContextPolicy is Application code/runtime wiring rather than durable Agent
|
|
212
|
+
state. The Policy object/descriptor is not persisted or reconstructed. A
|
|
213
|
+
finalized `LLMInputManifest` remains the Recovery authority for an already-fixed
|
|
214
|
+
Provider input.
|
|
215
|
+
|
|
216
|
+
No Phronomy Persistence transaction spans `ContextPolicy#call`. Context is
|
|
217
|
+
prepared from an immutable snapshot outside the transaction, then the durable
|
|
218
|
+
base/revision is revalidated before the short Manifest/execution commit.
|
|
219
|
+
|
|
220
|
+
The Context assembly policy version is now `8` because the semantic input/Plan
|
|
221
|
+
contract, Tool subset handling, Policy-generated current-call material, and
|
|
222
|
+
transaction boundary changed. Persisted Manifest readers that validate this
|
|
223
|
+
version should accept version 8.
|
|
224
|
+
|
|
225
|
+
## Workflow instance identity
|
|
226
|
+
|
|
227
|
+
Workflow durable identity is a clean rename:
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
thread_id
|
|
231
|
+
-> workflow_instance_id
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The new name identifies one logical Workflow instance and is also the logical
|
|
235
|
+
key supplied to `Persistence#workflow_states`.
|
|
236
|
+
|
|
237
|
+
Application code must change Workflow invocation configuration and live signals:
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
workflow.invoke(
|
|
241
|
+
input,
|
|
242
|
+
config: {workflow_instance_id: "order-123"}
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
workflow.signal(
|
|
246
|
+
workflow_instance_id: "order-123",
|
|
247
|
+
event: :external_result,
|
|
248
|
+
payload: result
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`WorkflowContext#thread_id` is removed and replaced by
|
|
253
|
+
`WorkflowContext#workflow_instance_id`. No deprecated alias is provided.
|
|
254
|
+
Supplying the old Workflow config key `:thread_id` raises `ArgumentError`
|
|
255
|
+
instead of silently allocating a new Workflow identity.
|
|
256
|
+
|
|
257
|
+
`workflow_instance_id` is framework-owned WorkflowContext metadata and is now a
|
|
258
|
+
reserved application field name. If an existing context declares
|
|
259
|
+
`field :workflow_instance_id`, rename that application field before upgrading;
|
|
260
|
+
0.22 rejects the declaration with `ArgumentError`.
|
|
261
|
+
|
|
262
|
+
The identifier value itself does not change. Existing durable key value
|
|
263
|
+
`"order-123"` remains `"order-123"` and is interpreted as the same
|
|
264
|
+
`workflow_instance_id`. Custom Persistence backends must rename the logical
|
|
265
|
+
parameter in their Workflow repository SPI, but a database adapter does not need
|
|
266
|
+
to rename a physical column solely for this migration.
|
|
267
|
+
|
|
268
|
+
`InvocationContext#thread_id` is not used as an implicit Workflow identity after
|
|
269
|
+
this change. CG-01 established the Workflow identity boundary; the generic Agent
|
|
270
|
+
invocation identity cleanup described below completes the separate Agent-side
|
|
271
|
+
removal.
|
|
272
|
+
|
|
273
|
+
## Generic Agent invocation identity
|
|
274
|
+
|
|
275
|
+
Agent-side generic invocation correlation is removed as a clean break.
|
|
276
|
+
|
|
277
|
+
Removed public surface:
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
InvocationContext#thread_id
|
|
281
|
+
InvocationContext#session_id
|
|
282
|
+
Agent#invoke(thread_id:)
|
|
283
|
+
Agent#invoke_async(thread_id:)
|
|
284
|
+
Agent#stream(thread_id:)
|
|
285
|
+
Agent#stream_async(thread_id:)
|
|
286
|
+
MultiAgent::Orchestrator#fan_out(thread_id:)
|
|
287
|
+
MultiAgent::Orchestrator#fan_out_async(thread_id:)
|
|
288
|
+
MultiAgent::Orchestrator#subagent(thread_id:)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
No `correlation_id`, `conversation_id`, or `application_session_id` replacement
|
|
292
|
+
is introduced. Applications that need correlation should keep it in their own
|
|
293
|
+
tracing/observability metadata or use the purpose-specific domain identifier
|
|
294
|
+
that owns the relevant lifecycle.
|
|
295
|
+
|
|
296
|
+
`InvocationContext#task_id` and `#parent_task_id` remain tracing/observability
|
|
297
|
+
identifiers. They are not Agent, Workflow, Tool, or Runtime routing identity.
|
|
298
|
+
|
|
299
|
+
Agent invocation config also rejects the removed `thread_id` and `session_id`
|
|
300
|
+
keys so the old generic identity cannot survive through an untyped config
|
|
301
|
+
backdoor.
|
|
302
|
+
|
|
303
|
+
The later CG-03b / ACS-10 Runtime foundation removes the shared generic
|
|
304
|
+
FSMSession graph-identity metadata bridge. Agent, Tool, and Multi-Agent routing
|
|
305
|
+
now uses concrete session-local sinks; Workflow metadata is passed explicitly as
|
|
306
|
+
`workflow_instance_id` while its admission-owner redesign remains ACS-13 work.
|
|
307
|
+
|
|
308
|
+
`JournalRecord#correlation_id` is also removed from the current canonical
|
|
309
|
+
Journal model and `JournalRecord#to_h` representation. New approval and
|
|
310
|
+
execution Journal records do not populate a generic correlation field.
|
|
311
|
+
|
|
312
|
+
Existing durable Journal Hashes are not rewritten merely to remove the legacy
|
|
313
|
+
key. `JournalRecord.from_h` accepts a legacy `correlation_id` key and ignores it
|
|
314
|
+
while restoring the current canonical fields. The same rule applies to legacy
|
|
315
|
+
Journal records nested in `AgentExecution#working_records`, because
|
|
316
|
+
`AgentExecution.from_h` delegates their reconstruction to `JournalRecord.from_h`.
|
|
317
|
+
|
|
318
|
+
Custom Persistence backends should stop producing `correlation_id` in new
|
|
319
|
+
canonical Journal representations. A backend does not need to rewrite every
|
|
320
|
+
existing stored row or drop a physical legacy column solely for this migration;
|
|
321
|
+
old values may remain backend-internal while legacy records are decoded into the
|
|
322
|
+
current correlation-free domain model.
|
|
323
|
+
|
|
324
|
+
## Agent execution parent identity
|
|
325
|
+
|
|
326
|
+
Tool and approval work now identifies its owning Agent execution with
|
|
327
|
+
`execution_id`. The old `agent_invocation_id` terminology is not retained as a
|
|
328
|
+
deprecated alias.
|
|
329
|
+
|
|
330
|
+
Application-facing changes:
|
|
331
|
+
|
|
332
|
+
```text
|
|
333
|
+
ToolApprovalRequest#agent_invocation_id
|
|
334
|
+
-> ToolApprovalRequest#execution_id
|
|
335
|
+
|
|
336
|
+
ToolApprovalRequest#to_h[:agent_invocation_id]
|
|
337
|
+
-> ToolApprovalRequest#to_h[:execution_id]
|
|
338
|
+
|
|
339
|
+
ApprovalEvaluationRequest#agent_invocation_id
|
|
340
|
+
-> ApprovalEvaluationRequest#execution_id
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
ACS-11 also makes Tool approval-policy input a value-only worker-boundary
|
|
344
|
+
contract. The live-object accessors are removed as a clean break:
|
|
345
|
+
|
|
346
|
+
```text
|
|
347
|
+
ApprovalEvaluationRequest#agent
|
|
348
|
+
-> #agent_id / #agent_definition_id / #agent_definition_version
|
|
349
|
+
|
|
350
|
+
ApprovalEvaluationRequest#tool
|
|
351
|
+
-> #tool_name / #tool_schema / #origin / #metadata
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
The authorization worker captures Tool approval behavior before offload and
|
|
355
|
+
does not receive a live Agent, Tool, or ToolInvocation object. Application
|
|
356
|
+
approval/facts/requirement callables remain supported as Application-owned
|
|
357
|
+
behavior handles.
|
|
358
|
+
|
|
359
|
+
`tool_invocation_id`, provider `tool_call_id`, and the approval request's own
|
|
360
|
+
`id` remain separate purpose-specific identifiers.
|
|
361
|
+
|
|
362
|
+
Agent invocation config also rejects `agent_invocation_id` so application code
|
|
363
|
+
cannot continue controlling the temporary Runtime routing identifier through an
|
|
364
|
+
untyped config key.
|
|
365
|
+
|
|
366
|
+
Suspended `AgentExecution` records created by an older version may contain
|
|
367
|
+
`approval_request["agent_invocation_id"]`. `AgentExecution.from_h` accepts that
|
|
368
|
+
legacy embedded shape, discards the old Runtime-oriented value, and derives the
|
|
369
|
+
current logical parent from the enclosing execution's own `execution_id`. It
|
|
370
|
+
does not reinterpret the historical `agent_invocation_id` value as an execution
|
|
371
|
+
ID.
|
|
372
|
+
|
|
373
|
+
Existing content-addressed approval audit bodies are not rewritten and may
|
|
374
|
+
retain their historical key. New approval request writes use `execution_id`.
|
|
375
|
+
This targeted compatibility handling does not define the general Persistence
|
|
376
|
+
schema/versioning policy.
|
|
377
|
+
|
|
378
|
+
CG-03b / ACS-10 now advances the Runtime routing half. `AgentInvocation` has no
|
|
379
|
+
independent routing ID or duplicate `session_id`; `ToolInvocation#id` remains
|
|
380
|
+
only the Tool lifecycle identity; and the private `parent_agent_invocation_id`
|
|
381
|
+
routing carrier is removed. Agent, Tool, and Multi-Agent concrete sessions use
|
|
382
|
+
fresh FSMSession IDs and session-local event sinks. Provider completion is routed
|
|
383
|
+
to the owning FSMSession and carries `llm_call_id` before any live result apply.
|
|
384
|
+
|
|
385
|
+
ACS-11 removes `AgentExecutionActivation` / `ActivationRegistry`: EventLoop is the
|
|
386
|
+
single writer of Phronomy-managed live Agent execution state, and operation-
|
|
387
|
+
specific Offload results are validated against current FSMSession/FSM state and
|
|
388
|
+
semantic IDs before apply. Together with ADR-023, this closes the Agent/Tool
|
|
389
|
+
CG-03 Runtime-foundation gap. Workflow opaque admission ownership remains
|
|
390
|
+
separate ACS-13 work.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Durable semantic coordination V2 migration
|
|
2
|
+
|
|
3
|
+
This Beta clean break applies to baseline `5472116cd99a63ec27875024c955ea82be612d6b`.
|
|
4
|
+
|
|
5
|
+
| Previous surface | Current surface |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `MultiAgent::Handoff`, `HandoffPolicy`, `Runner` | `Agent::Handoff`, `HandoffPolicy`, `HandoffRunner` (no aliases) |
|
|
8
|
+
| Runtime-local Handoff routing | HandoffState at original main Agent ID; same Persistence domain required |
|
|
9
|
+
| Anonymous Team/new Runtime queue | Explicit `team_definition id:, version:` and stable `team_id`; TeamRoot/TeamExecution |
|
|
10
|
+
| Arbitrary aggregate object/error exception result | Pure replay-safe aggregate, canonical JSON result/error data |
|
|
11
|
+
| Five backend repositories | Eight mandatory repositories; extend root and transaction views |
|
|
12
|
+
| Direct standalone fan-out | Remains Runtime-only; no synthetic parent AgentExecution |
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
class WorkTeam < Phronomy::MultiAgent::TeamCoordinator
|
|
16
|
+
team_definition id: "work-team", version: 1
|
|
17
|
+
coordinator_model "gpt-4o-mini"
|
|
18
|
+
coordinator_provider :openai
|
|
19
|
+
pool size: 2, agent: WorkerAgent
|
|
20
|
+
aggregate { |assignments| assignments.map { |a| a[:result] }.compact.join("\n") }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
team = WorkTeam.create(team_id: "team-42", persistence: store)
|
|
24
|
+
value = team.invoke("Prepare the report")
|
|
25
|
+
runs = store.list_team_executions("team-42")
|
|
26
|
+
run_id = runs.first.team_execution_id
|
|
27
|
+
retained = store.team_execution_result(run_id)
|
|
28
|
+
# After a restart with the same declared Team and worker definitions:
|
|
29
|
+
team = WorkTeam.load("team-42", persistence: store, on_event: recovery_listener)
|
|
30
|
+
value = team.resume(run_id)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`resume` consumes a stored terminal outcome without running the aggregator again.
|
|
34
|
+
For unfinished runs, stored input/context/assignments and child reservations win.
|
|
35
|
+
Compatible current Agent/Team classes, static registrations and Handoff graph are
|
|
36
|
+
execution wiring, not serialized objects. Version matching checks declarations;
|
|
37
|
+
Application must change versions for incompatible behavior and retain compatible
|
|
38
|
+
wiring for old runs. It is not a source-code hash or automatic migration system.
|
|
39
|
+
|
|
40
|
+
Use `Persistence#execution_result(id)` and owner-scoped `list_executions` for Agent
|
|
41
|
+
results without hydration/callbacks. `Persistence#handoff_result(source_id)`
|
|
42
|
+
follows the exact transfer chain without constructing a graph or Agent owners. `Orchestrator#resume(id)` continues existing
|
|
43
|
+
static subagent coordination. There is no global generic class registry.
|
|
44
|
+
|
|
45
|
+
Observer Task wait timeouts and shutdown do not request cancellation. Team's
|
|
46
|
+
`cancel(run_id)` persists a run-scoped request before forwarding its live token;
|
|
47
|
+
resume settles exact children or returns the existing rehydration error. Handoff's
|
|
48
|
+
`cancel(execution_id)` follows only that turn. A cancellation token passed to
|
|
49
|
+
invoke remains the existing Agent execution cancellation mechanism; it does not
|
|
50
|
+
promise rollback of external effects. Persisted pending child IDs remain
|
|
51
|
+
available for recovery when external factual resolution is required.
|
|
52
|
+
|
|
53
|
+
Callbacks and streaming progress may be lost after Runtime/process loss.
|
|
54
|
+
Application notifications, outboxes, retries and external-effect deduplication
|
|
55
|
+
belong to Application. No callback delivery ACK or restart replay is added.
|
|
56
|
+
InMemory is useful for tests but a durable backend is required for actual F4
|
|
57
|
+
storage retention. See ADR-018 and the V2 RC contract for guarantee limits.
|
|
58
|
+
|
|
59
|
+
The existing `Agent#purge!` removes its own Handoff anchor atomically with its
|
|
60
|
+
Agent records, after the anchor has no pending/active turn. Referenced outcomes
|
|
61
|
+
deleted through retention/purge are unavailable, not evidence of a new reservation.
|
|
62
|
+
Do not purge participating child/Target owners while their coordination is active.
|
|
63
|
+
Team `stream` observes committed assignment progress; the construction `on_event`
|
|
64
|
+
listener is passed to hidden Agents for their current Runtime events and Recovery.
|
|
65
|
+
There is no additional Team callback delivery subsystem.
|