phronomy 0.3.0 → 0.4.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/CHANGELOG.md +39 -0
- data/README.md +80 -12
- data/lib/phronomy/agent/base.rb +8 -3
- data/lib/phronomy/agent/orchestrator.rb +119 -0
- data/lib/phronomy/agent/shared_state.rb +303 -0
- data/lib/phronomy/agent/team_coordinator.rb +285 -0
- data/lib/phronomy/{trust_pipeline.rb → generator_verifier.rb} +95 -108
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow_runner.rb +41 -22
- data/lib/phronomy.rb +17 -0
- metadata +8 -6
|
@@ -137,20 +137,42 @@ module Phronomy
|
|
|
137
137
|
current_node = from_node || @entry_point
|
|
138
138
|
tracker = new_phase_machine(current_node)
|
|
139
139
|
tracker.context = state
|
|
140
|
+
# Event queue: decouple node execution from transition firing.
|
|
141
|
+
# Events are enqueued after a node completes and processed at the top
|
|
142
|
+
# of the next iteration so that guards always see the freshest context.
|
|
143
|
+
event_queue = []
|
|
140
144
|
step = 0
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
if
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
loop do
|
|
147
|
+
break if current_node == FINISH
|
|
148
|
+
|
|
149
|
+
# -- Process next pending event -----------------------------------------
|
|
150
|
+
# Dequeue one event and fire it against the state machine. Guards are
|
|
151
|
+
# evaluated here (at fire time) so they see the context written by the
|
|
152
|
+
# node that enqueued the event.
|
|
153
|
+
if (event = event_queue.shift)
|
|
154
|
+
if step >= recursion_limit
|
|
155
|
+
raise Phronomy::RecursionLimitError,
|
|
156
|
+
"Recursion limit (#{recursion_limit}) exceeded"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
fire_event!(tracker, event, current_node)
|
|
160
|
+
next_phase = tracker.phase.to_sym
|
|
161
|
+
# When next_phase == current_node no transition matched → terminal node.
|
|
162
|
+
current_node = (next_phase == current_node) ? FINISH : next_phase
|
|
163
|
+
step += 1
|
|
164
|
+
next
|
|
146
165
|
end
|
|
147
166
|
|
|
148
|
-
#
|
|
167
|
+
# -- Queue empty: check for halt -----------------------------------------
|
|
168
|
+
# Auto-halt at wait states: persist phase in context and return to caller.
|
|
169
|
+
# The caller resumes via send_event, which starts a fresh run_graph call.
|
|
149
170
|
if @wait_state_names.include?(current_node)
|
|
150
171
|
state.set_graph_metadata(thread_id: state.thread_id, phase: current_node)
|
|
151
172
|
return state
|
|
152
173
|
end
|
|
153
174
|
|
|
175
|
+
# -- Execute node action ------------------------------------------------
|
|
154
176
|
node_fn = @nodes[current_node]
|
|
155
177
|
raise ArgumentError, "Node #{current_node.inspect} is not defined" unless node_fn
|
|
156
178
|
|
|
@@ -165,27 +187,22 @@ module Phronomy
|
|
|
165
187
|
"expected Hash, #{@state_class}, or nil"
|
|
166
188
|
end
|
|
167
189
|
|
|
168
|
-
# Update tracker so guards see the freshest context.
|
|
190
|
+
# Update tracker so guards see the freshest context when the event fires.
|
|
169
191
|
tracker.context = state
|
|
170
192
|
|
|
171
193
|
event_block&.call({node: current_node, state: state})
|
|
172
194
|
|
|
173
|
-
#
|
|
195
|
+
# -- Enqueue transition event -------------------------------------------
|
|
196
|
+
# node_completed: generic event for all after-transitions (unconditional).
|
|
197
|
+
# route event: user-named event carrying guarded conditional branches.
|
|
198
|
+
# No enqueue: terminal node — next iteration exits via FINISH check.
|
|
174
199
|
if @after_transitions.key?(current_node)
|
|
175
|
-
|
|
200
|
+
event_queue << :node_completed
|
|
176
201
|
elsif @route_transitions.key?(current_node)
|
|
177
|
-
|
|
178
|
-
|
|
202
|
+
event_queue << @route_transitions[current_node][:event_name]
|
|
203
|
+
else
|
|
204
|
+
current_node = FINISH
|
|
179
205
|
end
|
|
180
|
-
# Nodes with no declared outgoing transition are treated as terminal:
|
|
181
|
-
# next_phase == current_node triggers the FINISH assignment below.
|
|
182
|
-
|
|
183
|
-
next_phase = tracker.phase.to_sym
|
|
184
|
-
# When next_phase == current_node: no transition fired (terminal node) → end.
|
|
185
|
-
# When next_phase == :__end__ (== FINISH): route led to finish → exit loop.
|
|
186
|
-
current_node = (next_phase == current_node) ? FINISH : next_phase
|
|
187
|
-
|
|
188
|
-
step += 1
|
|
189
206
|
end
|
|
190
207
|
|
|
191
208
|
state.set_graph_metadata(thread_id: state.thread_id, phase: :__end__)
|
|
@@ -225,9 +242,11 @@ module Phronomy
|
|
|
225
242
|
state_machine :phase, initial: entry do
|
|
226
243
|
all_states.each { |s| state s }
|
|
227
244
|
|
|
228
|
-
# 1. After-transitions:
|
|
229
|
-
|
|
230
|
-
|
|
245
|
+
# 1. After-transitions: one generic :node_completed event covers all
|
|
246
|
+
# unconditional transitions. This keeps event names independent of
|
|
247
|
+
# source state names and matches standard state machine semantics.
|
|
248
|
+
event :node_completed do
|
|
249
|
+
after_trans.each do |from, to|
|
|
231
250
|
transition from => to
|
|
232
251
|
end
|
|
233
252
|
end
|
data/lib/phronomy.rb
CHANGED
|
@@ -27,6 +27,23 @@ module Phronomy
|
|
|
27
27
|
|
|
28
28
|
class HandoffError < Error; end
|
|
29
29
|
|
|
30
|
+
# Raised by {Phronomy::GeneratorVerifier#invoke} when +raise_if_untrusted: true+
|
|
31
|
+
# and the pipeline's combined confidence score falls below the configured threshold.
|
|
32
|
+
#
|
|
33
|
+
# @example
|
|
34
|
+
# rescue Phronomy::LowConfidenceError => e
|
|
35
|
+
# puts e.result.confidence # => e.g. 0.45
|
|
36
|
+
# puts e.result.output # best-effort answer despite low confidence
|
|
37
|
+
class LowConfidenceError < Error
|
|
38
|
+
# @return [Phronomy::GeneratorVerifier::Result] the untrusted result
|
|
39
|
+
attr_reader :result
|
|
40
|
+
|
|
41
|
+
def initialize(result)
|
|
42
|
+
@result = result
|
|
43
|
+
super("Answer confidence #{result.confidence} is below the required threshold")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
30
47
|
class GuardrailError < Error
|
|
31
48
|
attr_reader :guardrail
|
|
32
49
|
|
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.4.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-05-
|
|
11
|
+
date: 2026-05-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -52,9 +52,8 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0.6'
|
|
55
|
-
description: Phronomy provides Agent, Workflow,
|
|
56
|
-
|
|
57
|
-
for LLM abstraction.
|
|
55
|
+
description: Phronomy provides Agent, Workflow, Tool, Guardrail, RAG, and Multi-agent
|
|
56
|
+
capabilities for building AI agents in Ruby. Powered by RubyLLM for LLM abstraction.
|
|
58
57
|
email:
|
|
59
58
|
- raizo.tcs@gmail.com
|
|
60
59
|
executables: []
|
|
@@ -75,9 +74,12 @@ files:
|
|
|
75
74
|
- lib/phronomy/agent/before_completion_context.rb
|
|
76
75
|
- lib/phronomy/agent/checkpoint.rb
|
|
77
76
|
- lib/phronomy/agent/handoff.rb
|
|
77
|
+
- lib/phronomy/agent/orchestrator.rb
|
|
78
78
|
- lib/phronomy/agent/react_agent.rb
|
|
79
79
|
- lib/phronomy/agent/runner.rb
|
|
80
|
+
- lib/phronomy/agent/shared_state.rb
|
|
80
81
|
- lib/phronomy/agent/suspend_signal.rb
|
|
82
|
+
- lib/phronomy/agent/team_coordinator.rb
|
|
81
83
|
- lib/phronomy/configuration.rb
|
|
82
84
|
- lib/phronomy/context.rb
|
|
83
85
|
- lib/phronomy/context/assembler.rb
|
|
@@ -103,6 +105,7 @@ files:
|
|
|
103
105
|
- lib/phronomy/eval/scorer/exact_match.rb
|
|
104
106
|
- lib/phronomy/eval/scorer/includes_scorer.rb
|
|
105
107
|
- lib/phronomy/eval/scorer/llm_judge.rb
|
|
108
|
+
- lib/phronomy/generator_verifier.rb
|
|
106
109
|
- lib/phronomy/guardrail.rb
|
|
107
110
|
- lib/phronomy/guardrail/base.rb
|
|
108
111
|
- lib/phronomy/guardrail/builtin.rb
|
|
@@ -142,7 +145,6 @@ files:
|
|
|
142
145
|
- lib/phronomy/tracing/langfuse_tracer.rb
|
|
143
146
|
- lib/phronomy/tracing/null_tracer.rb
|
|
144
147
|
- lib/phronomy/tracing/open_telemetry_tracer.rb
|
|
145
|
-
- lib/phronomy/trust_pipeline.rb
|
|
146
148
|
- lib/phronomy/vector_store.rb
|
|
147
149
|
- lib/phronomy/vector_store/base.rb
|
|
148
150
|
- lib/phronomy/vector_store/in_memory.rb
|