phronomy 0.16.0 → 0.18.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +8 -9
  3. data/CHANGELOG.md +151 -1134
  4. data/CONTRIBUTING.md +28 -16
  5. data/README.md +69 -1249
  6. data/benchmark/baseline.json +2 -3
  7. data/benchmark/bench_agent_invoke.rb +4 -4
  8. data/benchmark/bench_context_assembler.rb +134 -34
  9. data/benchmark/bench_regression.rb +26 -6
  10. data/benchmark/bench_tool_schema.rb +2 -35
  11. data/docs/changelog/0.14-and-earlier.md +1137 -0
  12. data/docs/decisions/005-static-knowledge-class-level-cache.md +12 -1
  13. data/docs/decisions/008-orchestrator-uses-os-threads.md +46 -48
  14. data/docs/decisions/010-cooperative-first-concurrency.md +155 -228
  15. data/docs/decisions/011-build-context-as-single-llm-input-authority.md +2 -2
  16. data/docs/decisions/013-journal-backed-knowledge-as-context-candidates.md +122 -0
  17. data/docs/features.md +87 -0
  18. data/docs/getting-started.md +351 -0
  19. data/docs/migrations/0.15.md +35 -0
  20. data/docs/migrations/0.16.md +43 -0
  21. data/docs/runtime-and-concurrency.md +258 -0
  22. data/examples/workflows/generic_task_event_mapping.rb +14 -6
  23. data/lib/phronomy/agent/agent_invocation.rb +2 -36
  24. data/lib/phronomy/agent/agent_invocation_session_builder.rb +157 -94
  25. data/lib/phronomy/agent/agent_root.rb +1 -2
  26. data/lib/phronomy/agent/async_event_api.rb +3 -3
  27. data/lib/phronomy/agent/base.rb +170 -333
  28. data/lib/phronomy/agent/context/capability/base.rb +177 -298
  29. data/lib/phronomy/agent/context_assembler.rb +65 -29
  30. data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +19 -89
  31. data/lib/phronomy/agent/context_plan_validator.rb +0 -33
  32. data/lib/phronomy/agent/execution_coordinator.rb +6 -7
  33. data/lib/phronomy/agent/journal_projection.rb +28 -2
  34. data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -111
  35. data/lib/phronomy/agent/shared_state.rb +48 -138
  36. data/lib/phronomy/agent/token_budget_resolver.rb +5 -4
  37. data/lib/phronomy/agent/tool_executor.rb +29 -71
  38. data/lib/phronomy/agent/tool_invocation.rb +180 -336
  39. data/lib/phronomy/agent/tool_invocation_session_builder.rb +55 -161
  40. data/lib/phronomy/agent.rb +6 -10
  41. data/lib/phronomy/configuration.rb +4 -171
  42. data/lib/phronomy/diagnostics.rb +12 -41
  43. data/lib/phronomy/engine/concurrency/async_queue.rb +5 -188
  44. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +6 -7
  45. data/lib/phronomy/engine/concurrency/cancellation_token.rb +51 -79
  46. data/lib/phronomy/engine/concurrency/deadline.rb +2 -3
  47. data/lib/phronomy/engine/concurrency/offload_pool.rb +696 -0
  48. data/lib/phronomy/engine/concurrency/pool_registry.rb +5 -5
  49. data/lib/phronomy/engine/event_loop.rb +89 -190
  50. data/lib/phronomy/engine/runtime/timer_queue.rb +48 -71
  51. data/lib/phronomy/engine/runtime/timer_service.rb +13 -21
  52. data/lib/phronomy/engine/runtime.rb +49 -377
  53. data/lib/phronomy/engine/task.rb +136 -277
  54. data/lib/phronomy/llm_adapter/base.rb +14 -14
  55. data/lib/phronomy/llm_adapter/ruby_llm.rb +3 -4
  56. data/lib/phronomy/llm_adapter.rb +2 -2
  57. data/lib/phronomy/llm_context_window/token_budget.rb +8 -79
  58. data/lib/phronomy/metrics.rb +15 -30
  59. data/lib/phronomy/multi_agent/fan_out_invocation.rb +146 -0
  60. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +125 -0
  61. data/lib/phronomy/multi_agent/handoff.rb +1 -0
  62. data/lib/phronomy/multi_agent/orchestrator.rb +252 -256
  63. data/lib/phronomy/multi_agent/team_coordinator.rb +44 -133
  64. data/lib/phronomy/testing/eval/comparison.rb +23 -0
  65. data/lib/phronomy/testing/eval/dataset.rb +27 -0
  66. data/lib/phronomy/testing/eval/eval_case.rb +13 -0
  67. data/lib/phronomy/testing/eval/eval_result.rb +16 -0
  68. data/lib/phronomy/testing/eval/metrics.rb +43 -0
  69. data/lib/phronomy/testing/eval/runner.rb +52 -0
  70. data/lib/phronomy/testing/eval/scorer/base.rb +15 -0
  71. data/lib/phronomy/testing/eval/scorer/exact_match.rb +25 -0
  72. data/lib/phronomy/testing/eval/scorer/includes_scorer.rb +25 -0
  73. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +46 -0
  74. data/lib/phronomy/testing/eval/scorer.rb +10 -0
  75. data/lib/phronomy/testing/eval.rb +9 -0
  76. data/lib/phronomy/testing/fake_clock.rb +6 -53
  77. data/lib/phronomy/testing.rb +2 -6
  78. data/lib/phronomy/tools/agent.rb +141 -6
  79. data/lib/phronomy/vector_store/async_backend.rb +21 -17
  80. data/lib/phronomy/vector_store/base.rb +2 -2
  81. data/lib/phronomy/vector_store/embeddings/base.rb +6 -5
  82. data/lib/phronomy/vector_store/in_memory.rb +2 -2
  83. data/lib/phronomy/version.rb +1 -1
  84. data/lib/phronomy/workflow_runner.rb +2 -4
  85. data/lib/phronomy.rb +7 -121
  86. data/scripts/api_snapshot.rb +4 -15
  87. metadata +24 -38
  88. data/lib/phronomy/agent/context/knowledge/base.rb +0 -58
  89. data/lib/phronomy/agent/context/knowledge/entity_knowledge.rb +0 -102
  90. data/lib/phronomy/agent/context/knowledge/static_knowledge.rb +0 -58
  91. data/lib/phronomy/agent/fsm_runtime_adapter.rb +0 -210
  92. data/lib/phronomy/engine/concurrency/blocking_adapter_pool.rb +0 -561
  93. data/lib/phronomy/engine/runtime/deterministic_scheduler.rb +0 -439
  94. data/lib/phronomy/engine/runtime/fake_scheduler.rb +0 -165
  95. data/lib/phronomy/engine/runtime/runtime_metrics.rb +0 -116
  96. data/lib/phronomy/engine/runtime/scheduler.rb +0 -98
  97. data/lib/phronomy/engine/runtime/scheduler_timer_adapter.rb +0 -79
  98. data/lib/phronomy/engine/runtime/task_registry.rb +0 -95
  99. data/lib/phronomy/engine/runtime/thread_scheduler.rb +0 -30
  100. data/lib/phronomy/engine/task/backend.rb +0 -80
  101. data/lib/phronomy/engine/task/deferred_backend.rb +0 -73
  102. data/lib/phronomy/engine/task/fiber_backend.rb +0 -157
  103. data/lib/phronomy/engine/task/immediate_backend.rb +0 -89
  104. data/lib/phronomy/engine/task/mapped_backend.rb +0 -90
  105. data/lib/phronomy/engine/task/thread_backend.rb +0 -84
  106. data/lib/phronomy/engine/task_group.rb +0 -265
  107. data/lib/phronomy/eval/comparison.rb +0 -47
  108. data/lib/phronomy/eval/dataset.rb +0 -45
  109. data/lib/phronomy/eval/eval_case.rb +0 -17
  110. data/lib/phronomy/eval/eval_result.rb +0 -29
  111. data/lib/phronomy/eval/metrics.rb +0 -66
  112. data/lib/phronomy/eval/runner.rb +0 -94
  113. data/lib/phronomy/eval/scorer/base.rb +0 -22
  114. data/lib/phronomy/eval/scorer/exact_match.rb +0 -31
  115. data/lib/phronomy/eval/scorer/includes_scorer.rb +0 -32
  116. data/lib/phronomy/eval/scorer/llm_judge.rb +0 -72
  117. data/lib/phronomy/eval/scorer.rb +0 -9
  118. data/lib/phronomy/eval.rb +0 -7
  119. data/lib/phronomy/knowledge_source.rb +0 -12
  120. data/lib/phronomy/llm_context_window/assembler.rb +0 -191
  121. data/lib/phronomy/llm_context_window/context_version_cache.rb +0 -52
  122. data/lib/phronomy/testing/fake_scheduler.rb +0 -104
  123. data/lib/phronomy/testing/scheduler_helpers.rb +0 -68
@@ -1,210 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Agent
5
- # Adapts the current AgentInvocation FSM to the ideal manifest-first model.
6
- # Every LLM Call receives a freshly fixed Manifest. Persistence and
7
- # projection preparation run on BlockingAdapterPool, never on EventLoop.
8
- module FsmRuntimeAdapter
9
- private
10
-
11
- def filtering_input_action(_agent, invocation)
12
- invocation.input = invocation.config.fetch(:phronomy_filtered_input)
13
- invocation
14
- end
15
-
16
- def building_context_action(agent, invocation)
17
- projection = invocation.config.fetch(:phronomy_runtime_projection)
18
- invocation.chat = agent.send(:build_chat, model_config: projection.model_config)
19
- agent.send(
20
- :_apply_context_to_chat,
21
- invocation.chat,
22
- {
23
- system: projection.system,
24
- messages: projection.messages,
25
- tool_classes: projection.tool_classes,
26
- model_config: projection.model_config
27
- }
28
- )
29
- install_tool_interceptors(invocation.chat, invocation)
30
- invocation
31
- end
32
-
33
- def calling_llm_action(agent, runtime, invocation)
34
- prepare_and_start_llm_call(
35
- agent,
36
- runtime,
37
- invocation,
38
- streaming: false
39
- )
40
- invocation
41
- end
42
-
43
- def calling_llm_stream_action(agent, runtime, invocation)
44
- prepare_and_start_llm_call(
45
- agent,
46
- runtime,
47
- invocation,
48
- streaming: true
49
- )
50
- invocation
51
- end
52
-
53
- def prepare_and_start_llm_call(agent, runtime, invocation, streaming:)
54
- activation = invocation.config.fetch(:phronomy_activation)
55
- if invocation.user_message_sent
56
- preparation = runtime.blocking_io.submit do
57
- activation.coordinator.prepare_next_llm_call(activation)
58
- end
59
- preparation.on_complete do |projection, error|
60
- if error
61
- post_preparation_failure(runtime, invocation, error, streaming: streaming)
62
- else
63
- start_provider_call(
64
- agent,
65
- runtime,
66
- invocation,
67
- activation,
68
- projection,
69
- streaming: streaming,
70
- replace_messages: true
71
- )
72
- end
73
- end
74
- else
75
- start_provider_call(
76
- agent,
77
- runtime,
78
- invocation,
79
- activation,
80
- activation.runtime_projection,
81
- streaming: streaming,
82
- replace_messages: false
83
- )
84
- end
85
- end
86
-
87
- def start_provider_call(
88
- agent,
89
- runtime,
90
- invocation,
91
- activation,
92
- projection,
93
- streaming:,
94
- replace_messages:
95
- )
96
- call_started = false
97
- agent.send(
98
- :check_cancellation!,
99
- invocation.config,
100
- "invocation cancelled before LLM call"
101
- )
102
- if replace_messages
103
- invocation.chat = agent.send(:build_chat, model_config: projection.model_config)
104
- agent.send(
105
- :_apply_context_to_chat,
106
- invocation.chat,
107
- {
108
- system: projection.system,
109
- messages: projection.messages,
110
- tool_classes: projection.tool_classes,
111
- model_config: projection.model_config
112
- }
113
- )
114
- install_tool_interceptors(invocation.chat, invocation)
115
- invocation.config[:phronomy_runtime_projection] = projection
116
- end
117
-
118
- call_context = activation.begin_llm_call(projection)
119
- call_started = true
120
- invocation.begin_llm_call!(call_context.fetch(:llm_call_id))
121
- message = projection.ask_message
122
-
123
- operation = if streaming
124
- Phronomy.configuration.llm_adapter.stream_async(
125
- invocation.chat,
126
- message,
127
- config: invocation.config
128
- ) do |chunk|
129
- agent.send(
130
- :check_cancellation!,
131
- invocation.config,
132
- "invocation cancelled during streaming"
133
- )
134
- post_to_invocation!(
135
- runtime,
136
- invocation.id,
137
- :llm_stream_chunk,
138
- {content: chunk.content}
139
- )
140
- end
141
- else
142
- Phronomy.configuration.llm_adapter.complete_async(
143
- invocation.chat,
144
- message,
145
- config: invocation.config
146
- )
147
- end
148
- observe_manifest_call(
149
- operation,
150
- activation,
151
- invocation,
152
- runtime: runtime,
153
- streaming: streaming
154
- )
155
- rescue => error
156
- if call_started
157
- activation.record_llm_result(
158
- response: canonical_response_for(nil, error),
159
- error: error,
160
- streaming: streaming
161
- )
162
- end
163
- post_llm_result(runtime, invocation, nil, error, streaming: streaming)
164
- end
165
-
166
- def observe_manifest_call(operation, activation, invocation, runtime:, streaming:)
167
- operation.on_complete do |response, error|
168
- activation.record_llm_result(
169
- response: canonical_response_for(response, error),
170
- error: error,
171
- streaming: streaming
172
- )
173
- post_llm_result(
174
- runtime,
175
- invocation,
176
- response,
177
- error,
178
- streaming: streaming
179
- )
180
- end
181
- end
182
-
183
- def canonical_response_for(response, error)
184
- if error.is_a?(ToolCallIntercepted)
185
- error.assistant_outcome || ProviderCallOutcome.capture(response)
186
- else
187
- ProviderCallOutcome.capture(response)
188
- end
189
- end
190
-
191
- def post_preparation_failure(runtime, invocation, error, streaming:)
192
- post_llm_result(runtime, invocation, nil, error, streaming: streaming)
193
- end
194
-
195
- def post_llm_result(runtime, invocation, response, error, streaming:)
196
- result = LLMOperationResult.new(
197
- response: response,
198
- error: error,
199
- streaming: streaming
200
- )
201
- event_type = if error && !error.is_a?(ToolCallIntercepted)
202
- :llm_failed
203
- else
204
- :llm_completed
205
- end
206
- post_to_invocation!(runtime, invocation.id, event_type, result)
207
- end
208
- end
209
- end
210
- end