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.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +3 -4
  3. data/CHANGELOG.md +215 -10
  4. data/CONTRIBUTING.md +81 -9
  5. data/README.md +15 -6
  6. data/VERIFY.sh +587 -0
  7. data/benchmark/bench_agent_invoke.rb +2 -2
  8. data/benchmark/bench_context_assembler.rb +39 -68
  9. data/benchmark/bench_regression.rb +2 -2
  10. data/docs/architecture/agent-context.md +174 -0
  11. data/docs/architecture/before-llm-input.md +78 -0
  12. data/docs/architecture/context-management.md +232 -0
  13. data/docs/architecture/knowledge-and-rag.md +130 -0
  14. data/docs/architecture/multi-agent-handoff.md +147 -0
  15. data/docs/architecture/persistence.md +186 -0
  16. data/docs/architecture/removed/agent-context.md +72 -0
  17. data/docs/architecture/security-boundaries.md +173 -0
  18. data/docs/architecture/tracing.md +194 -0
  19. data/docs/architecture.md +89 -0
  20. data/docs/archive/design/archived/04_api_design.md +507 -0
  21. data/docs/archive/design/archived/09_guardrails.md +186 -0
  22. data/docs/archive/design/archived/17_rails_integration.md +175 -0
  23. data/docs/archive/design/historical/00_design_philosophy.md +122 -0
  24. data/docs/archive/design/historical/01_rubyllm_evaluation.md +178 -0
  25. data/docs/archive/design/historical/06_design_decisions.md +143 -0
  26. data/docs/changelog/0.14-and-earlier.md +1 -1
  27. data/docs/decisions/001-rubyllm-as-provider-layer.md +6 -1
  28. data/docs/decisions/002-workflow-context-immutability.md +26 -1
  29. data/docs/decisions/006-no-built-in-guardrails.md +2 -1
  30. data/docs/decisions/012-canonical-execution-log-and-context-policy.md +120 -38
  31. data/docs/decisions/014-unified-persistence-durable-state.md +9 -2
  32. data/docs/decisions/016-semantic-multi-agent-handoff.md +114 -0
  33. data/docs/decisions/017-design-authority-and-adr-governance.md +200 -0
  34. data/docs/decisions/018-durability-guarantees-and-failure-model.md +488 -0
  35. data/docs/decisions/019-filter-contract-and-security-boundaries.md +229 -0
  36. data/docs/decisions/020-canonical-workflow-instance-identity.md +177 -0
  37. data/docs/decisions/021-generic-agent-invocation-identity-removal.md +119 -0
  38. data/docs/decisions/022-agent-execution-parent-identity-and-runtime-routing-boundary.md +193 -0
  39. data/docs/decisions/023-fsm-session-incarnation-identity-and-routing.md +139 -0
  40. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +188 -0
  41. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +249 -0
  42. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +257 -0
  43. data/docs/decisions/027-llm-adapter-provider-boundary.md +93 -0
  44. data/docs/decisions/028-preparing-recovery-replay-contract.md +106 -0
  45. data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +220 -0
  46. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +235 -0
  47. data/docs/decisions/031-durable-multi-agent-coordination.md +301 -0
  48. data/docs/decisions/README.md +176 -0
  49. data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +33 -0
  50. data/docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md +191 -0
  51. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +862 -0
  52. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +106 -0
  53. data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +179 -0
  54. data/docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md +302 -0
  55. data/docs/features.md +65 -11
  56. data/docs/getting-started.md +77 -45
  57. data/docs/migrations/0.19.md +14 -7
  58. data/docs/migrations/0.22.md +390 -0
  59. data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
  60. data/docs/persistence-backends.md +129 -40
  61. data/docs/runtime-and-concurrency.md +227 -33
  62. data/examples/README.md +13 -0
  63. data/lib/phronomy/agent/agent_execution.rb +21 -17
  64. data/lib/phronomy/agent/agent_invocation.rb +288 -93
  65. data/lib/phronomy/agent/agent_invocation_session_builder.rb +236 -202
  66. data/lib/phronomy/agent/agent_root.rb +3 -3
  67. data/lib/phronomy/agent/approval_evaluation_request.rb +37 -19
  68. data/lib/phronomy/agent/async_event_api.rb +162 -72
  69. data/lib/phronomy/agent/base.rb +416 -181
  70. data/lib/phronomy/agent/concerns/before_llm_input.rb +1 -1
  71. data/lib/phronomy/agent/context_assembler.rb +437 -178
  72. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  73. data/lib/phronomy/agent/context_plan.rb +18 -13
  74. data/lib/phronomy/agent/context_plan_validator.rb +246 -88
  75. data/lib/phronomy/agent/context_policies/default.rb +123 -34
  76. data/lib/phronomy/agent/context_policy.rb +109 -3
  77. data/lib/phronomy/agent/context_policy_input.rb +244 -0
  78. data/lib/phronomy/agent/context_policy_input_builder.rb +241 -0
  79. data/lib/phronomy/agent/exact_execution.rb +153 -0
  80. data/lib/phronomy/agent/execution_cancellation.rb +25 -0
  81. data/lib/phronomy/agent/execution_coordinator.rb +2417 -572
  82. data/lib/phronomy/agent/handoff.rb +43 -0
  83. data/lib/phronomy/agent/handoff_capability_factory.rb +45 -0
  84. data/lib/phronomy/agent/handoff_context.rb +120 -0
  85. data/lib/phronomy/agent/handoff_execution_coordinator.rb +143 -0
  86. data/lib/phronomy/agent/handoff_policy.rb +143 -0
  87. data/lib/phronomy/agent/handoff_projection.rb +207 -0
  88. data/lib/phronomy/agent/handoff_request.rb +45 -0
  89. data/lib/phronomy/agent/handoff_runner.rb +178 -0
  90. data/lib/phronomy/agent/handoff_state.rb +43 -0
  91. data/lib/phronomy/agent/journal_record.rb +17 -4
  92. data/lib/phronomy/agent/llm_input_build_context.rb +1 -1
  93. data/lib/phronomy/agent/llm_input_manifest.rb +277 -2
  94. data/lib/phronomy/agent/llm_operation_result.rb +12 -7
  95. data/lib/phronomy/agent/phase_machine_builder.rb +19 -7
  96. data/lib/phronomy/agent/provider_call_outcome.rb +23 -7
  97. data/lib/phronomy/agent/recovery_coordinator/continuation.rb +174 -0
  98. data/lib/phronomy/agent/recovery_coordinator/installation.rb +381 -0
  99. data/lib/phronomy/agent/recovery_coordinator/resolution.rb +511 -0
  100. data/lib/phronomy/agent/recovery_coordinator.rb +217 -0
  101. data/lib/phronomy/agent/recovery_support.rb +504 -0
  102. data/lib/phronomy/agent/ruby_llm_materializer.rb +16 -13
  103. data/lib/phronomy/agent/selection/candidate.rb +53 -0
  104. data/lib/phronomy/agent/selection/constraint.rb +49 -0
  105. data/lib/phronomy/agent/shared_state.rb +38 -1
  106. data/lib/phronomy/agent/tool_approval_request.rb +33 -5
  107. data/lib/phronomy/agent/tool_definition_set.rb +49 -3
  108. data/lib/phronomy/agent/tool_invocation.rb +339 -103
  109. data/lib/phronomy/agent/tool_invocation_session_builder.rb +49 -45
  110. data/lib/phronomy/agent.rb +20 -2
  111. data/lib/phronomy/agent_already_exists_error.rb +5 -0
  112. data/lib/phronomy/agent_purged_error.rb +5 -0
  113. data/lib/phronomy/engine/concurrency/offload_pool.rb +17 -3
  114. data/lib/phronomy/engine/concurrency/physical_completion_task.rb +135 -0
  115. data/lib/phronomy/engine/event_loop.rb +622 -63
  116. data/lib/phronomy/engine/fsm_session.rb +194 -21
  117. data/lib/phronomy/engine/runtime/agent_ownership_registry.rb +352 -0
  118. data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
  119. data/lib/phronomy/engine/runtime.rb +92 -20
  120. data/lib/phronomy/generator_verifier.rb +12 -14
  121. data/lib/phronomy/invocation_context.rb +9 -29
  122. data/lib/phronomy/multi_agent/admission_registry.rb +51 -0
  123. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
  124. data/lib/phronomy/multi_agent/fan_out_invocation.rb +24 -33
  125. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +12 -19
  126. data/lib/phronomy/multi_agent/orchestrator.rb +71 -26
  127. data/lib/phronomy/multi_agent/team_coordinator.rb +473 -125
  128. data/lib/phronomy/multi_agent/team_execution.rb +44 -0
  129. data/lib/phronomy/multi_agent/team_root.rb +41 -0
  130. data/lib/phronomy/persistence/durable_codec.rb +706 -0
  131. data/lib/phronomy/persistence/durable_record.rb +117 -0
  132. data/lib/phronomy/persistence/in_memory.rb +471 -133
  133. data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
  134. data/lib/phronomy/persistence/repository_facades.rb +535 -0
  135. data/lib/phronomy/persistence.rb +174 -40
  136. data/lib/phronomy/recovery.rb +186 -0
  137. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  138. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +2 -1
  139. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +19 -19
  140. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +3 -3
  141. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  142. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +137 -0
  143. data/lib/phronomy/testing/persistence_contract.rb +5 -0
  144. data/lib/phronomy/tools/agent.rb +1 -1
  145. data/lib/phronomy/tracing/automatic.rb +176 -0
  146. data/lib/phronomy/tracing/base.rb +11 -2
  147. data/lib/phronomy/tracing/langfuse_tracer.rb +20 -12
  148. data/lib/phronomy/version.rb +1 -1
  149. data/lib/phronomy/workflow.rb +3 -6
  150. data/lib/phronomy/workflow_context.rb +14 -5
  151. data/lib/phronomy/workflow_recovery.rb +123 -0
  152. data/lib/phronomy/workflow_runner.rb +468 -256
  153. data/lib/phronomy.rb +6 -0
  154. data/scripts/api_snapshot.rb +12 -0
  155. data/sig/phronomy/agent.rbs +209 -7
  156. data/sig/phronomy/handoff.rbs +41 -0
  157. data/sig/phronomy/multi_agent.rbs +35 -0
  158. data/sig/phronomy/persistence.rbs +123 -4
  159. data/sig/phronomy/runtime.rbs +1 -4
  160. data/sig/phronomy/workflow.rbs +2 -2
  161. data/sig/phronomy.rbs +10 -0
  162. metadata +84 -18
  163. data/examples/workflows/agent_event_mapping.rb +0 -101
  164. data/examples/workflows/generic_task_event_mapping.rb +0 -66
  165. data/lib/phronomy/agent/activation_registry.rb +0 -28
  166. data/lib/phronomy/agent/agent_execution_activation.rb +0 -172
  167. data/lib/phronomy/agent/context_candidate.rb +0 -47
  168. data/lib/phronomy/agent/context_parts/budget/token_budget_packer.rb +0 -53
  169. data/lib/phronomy/agent/context_parts/requirements/required_context_resolver.rb +0 -56
  170. data/lib/phronomy/agent/context_parts/selectors/recent_first_selector.rb +0 -30
  171. data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +0 -118
  172. data/lib/phronomy/agent/context_policy_descriptor.rb +0 -49
  173. data/lib/phronomy/agent/context_policy_registry.rb +0 -46
  174. data/lib/phronomy/agent/context_request.rb +0 -35
  175. data/lib/phronomy/agent/context_selection_unit.rb +0 -38
  176. data/lib/phronomy/agent/derived_content_spec.rb +0 -34
  177. data/lib/phronomy/agent/runner.rb +0 -97
  178. 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.