phronomy 0.3.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb874213c4687c9021be3c78d8972218ed56980cfff777a624311ce476d7314
4
- data.tar.gz: ab3017e56357b057943d31a557e9e1cd12555ec13924fbee92c6f0f7791c9bd1
3
+ metadata.gz: 138e6b7d6b59f34f827e39a43b86c6f30ea0dd80e936d11e326febad4d3217b0
4
+ data.tar.gz: fada502e034850a3162a488cb02fc195364fc93e72398e858a79058c005c2ad3
5
5
  SHA512:
6
- metadata.gz: e3d71a750858fda7910addd2ea8de1a3b907e746a247635d0b7467b4ffb5cf1ca970e74a08118b58e950c5843f756462d87a324331d23f50720067a83bb87590
7
- data.tar.gz: 5ce1868de692cd6807c910f3d4669791307564c5f3dc58055c82c4c0737e3696c0d5b1050e7b85f1aba30b1e6309c11e66fcbf7ffc4f9f6c63f3970b5bce2d52
6
+ metadata.gz: 55526d56e69e328f9de38e75da98a9a1e0d206997f3463a18aa0481f18d978896f02567a0fefcb6ec4fe2a5f030d3829dde59c479305f6e3ce9d825b06222ce8
7
+ data.tar.gz: f58b275260866c5a7784c32c9846c9058cab815d6d294b92041dcf29525bbf76e1683c1151991c092eace65e5e55e41ad5390d6f6106f9306aa053bf42c5c0a8
data/CHANGELOG.md CHANGED
@@ -7,6 +7,89 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.5.0] - 2026-05-20
11
+
12
+ ### Breaking Changes
13
+
14
+ - **`Agent::Base#invoke` and `#stream` — `messages` and `thread_id` promoted to
15
+ top-level keyword arguments**:
16
+ Previously these values were passed inside the `config:` hash. They are now
17
+ explicit keyword arguments. The `config:` hash retains other runtime options
18
+ such as `:knowledge_sources`, `:user_id`, and `:session_id`.
19
+
20
+ **Before (v0.4.x)**:
21
+ ```ruby
22
+ agent.invoke(input, config: { messages: prior_msgs, thread_id: "t1" })
23
+ agent.stream(input, config: { messages: prior_msgs, thread_id: "t1" }) { |e| ... }
24
+ ```
25
+ **After (v0.5.0)**:
26
+ ```ruby
27
+ agent.invoke(input, messages: prior_msgs, thread_id: "t1")
28
+ agent.stream(input, messages: prior_msgs, thread_id: "t1") { |e| ... }
29
+ ```
30
+ Applications that only pass `:knowledge_sources`, `:user_id`, or `:session_id`
31
+ in `config:` require no changes.
32
+
33
+ - **`Agent::Checkpoint#initialize` — `original_input:` is now a required keyword
34
+ argument**: Applications that construct `Checkpoint` instances directly must
35
+ add `original_input: input`. Checkpoints produced by `#invoke` already include
36
+ this field automatically.
37
+
38
+ ### Fixed
39
+
40
+ - **`ReactAgent#step` — system instructions were never applied**: The first
41
+ iteration of the ReAct loop now calls `build_context` to assemble the system
42
+ prompt and history, matching the behaviour of `Agent::Base`. Subsequent
43
+ iterations re-apply instructions via `build_cached_system_text` before calling
44
+ `chat.complete`. Previously, all iterations silently omitted the system prompt.
45
+
46
+ - **`Agent::Base#resume` — system instructions were not re-applied after
47
+ suspension**: Resuming from a `Checkpoint` now calls `build_cached_system_text`
48
+ using the original input stored in the checkpoint, so the LLM receives the
49
+ correct system prompt when the conversation continues. Previously, the LLM was
50
+ called without any system instructions on resume.
51
+
52
+ ---
53
+
54
+ ## [0.4.0] - 2026-05-19
55
+
56
+ ### Removed
57
+
58
+ - **`Phronomy::TrustPipeline` removed**: The `TrustPipeline` class and its inner
59
+ `TrustResult` value object have been deleted. Use `Phronomy::GeneratorVerifier`
60
+ instead, which provides the same generator-verifier pattern with a cleaner,
61
+ fully injectable API.
62
+
63
+ ### Added
64
+
65
+ - **`Phronomy::GeneratorVerifier`** — Generator-Verifier coordination loop
66
+ (Anthropic blog, Pattern 1). Wraps a generator agent and a verifier agent with
67
+ fully injectable prompt builders, response parsers, a configurable iteration
68
+ limit, and an approval-outcome raise policy.
69
+ - **`Phronomy::Agent::Orchestrator`** — Base class for orchestrator agents
70
+ (Anthropic blog, Pattern 2). Extends `Agent::Base` with a `subagent` DSL for
71
+ declarative subagent registration as LLM-callable tools, plus `dispatch_parallel`
72
+ and `fan_out` for programmatic parallel invocation.
73
+ - **`Phronomy::Agent::TeamCoordinator`** — Agent teams coordination pattern
74
+ (Anthropic blog, Pattern 3). An LLM-powered coordinator with a shared task
75
+ queue and a pool of worker agents that carry conversation history across task
76
+ assignments. Adds `coordinator_provider` DSL for independent LLM routing.
77
+ - **`Phronomy::Agent::SharedState`** — Shared-state coordination pattern
78
+ (Anthropic blog, Pattern 5). Peer agents collaborate via a `KnowledgeStore`;
79
+ the `member` DSL registers agents with per-agent instructions; `coordination`
80
+ sets the team protocol; `build_prompt` injects a tool-usage guide automatically.
81
+ - **`Phronomy::LowConfidenceError`** — Exception raised by `GeneratorVerifier`
82
+ when `raise_policy: :raise` and verification fails after exhausting the
83
+ iteration limit.
84
+
85
+ ### Changed
86
+
87
+ - **`Phronomy::Graph::StateGraph` event system refactored**: Per-node `advance`
88
+ events replaced with a unified `node_completed` event queue, reducing
89
+ event-handler registration overhead and simplifying listener registration.
90
+
91
+ ---
92
+
10
93
  ## [0.3.0] - 2026-05-18
11
94
 
12
95
  ### Removed
data/README.md CHANGED
@@ -18,7 +18,10 @@ It provides composable building blocks — Workflows, Agents, Tools, Guardrails,
18
18
  | **Context Management** — Token budget calculation, estimation, and pruning | Stable |
19
19
  | **Knowledge/RAG** — Retrieval sources with pluggable loaders, splitters, and vector stores | Beta |
20
20
  | **Multi-agent** — Agent-as-Tool pattern and hub-and-spoke handoff routing | Beta |
21
- | **TrustPipeline** — Self-review loop and confidence gate (citations are LLM-self-reported) | Experimental |
21
+ | **GeneratorVerifier** — Generator-Verifier loop with injectable prompt builders/parsers | Beta |
22
+ | **Agent::Orchestrator** — Parallel subagent dispatch, fan-out, and `subagent` DSL | Beta |
23
+ | **Agent::TeamCoordinator** — Agent teams pattern: LLM coordinator + persistent worker pool with task queue | Beta |
24
+ | **Agent::SharedState** — Shared state pattern: peer agents collaborate via a shared KnowledgeStore; `member` DSL with per-agent instructions and `coordination` team protocol | Experimental |
22
25
  | **Guardrails** — Input/output validation; built-in PII and prompt-injection detectors | Beta |
23
26
  | **Output Parser** — JSON and Struct-mapped parsers for structured LLM responses | Stable |
24
27
  | **Eval Framework** — Dataset-driven evaluation with multiple scorer types | Beta |
@@ -226,23 +229,88 @@ end
226
229
 
227
230
  Hooks are called in order — global → class → instance — and deep-merged.
228
231
 
229
- ### TrustPipelineTrustworthy outputs with citations and review
232
+ ### GeneratorVerifierGenerator-Verifier loop with custom prompt builders
230
233
 
231
234
  ```ruby
232
- pipeline = Phronomy::TrustPipeline.new(
233
- draft_agent: PolicyDraftAgent,
234
- review_agent: PolicyReviewAgent,
235
+ pipeline = Phronomy::GeneratorVerifier.new(
236
+ draft_agent: PolicyDraftAgent,
237
+ review_agent: PolicyReviewAgent,
238
+
239
+ # Full control over the LLM dialogue — supply your own prompts.
240
+ draft_prompt_builder: ->(input, feedback) {
241
+ base = "Answer precisely: #{input}"
242
+ feedback ? "#{base}\n\nPrevious feedback: #{feedback}" : base
243
+ },
244
+ review_prompt_builder: ->(input, draft, citations) {
245
+ "Is this draft accurate? Draft: #{draft}"
246
+ },
247
+
235
248
  confidence_threshold: 0.7,
236
- max_iterations: 3
249
+ max_iterations: 3,
250
+ raise_if_untrusted: false # set true to raise LowConfidenceError
237
251
  )
238
252
 
239
253
  result = pipeline.invoke("What is the refund policy?")
240
- puts result.output # final answer
241
- puts result.trusted? # true when confidence >= 0.7
242
- puts result.confidence # Float 0.0–1.0
254
+ puts result.output # final answer
255
+ puts result.trusted? # true when confidence >= 0.7
256
+ puts result.confidence # Float 0.0–1.0
257
+ result.citations.each { |c| puts "#{c[:source]}: #{c[:excerpt]}" }
258
+ ```
259
+
260
+ Optionally inject a custom result parser to decode non-JSON LLM output:
261
+
262
+ ```ruby
263
+ pipeline = Phronomy::GeneratorVerifier.new(
264
+ # ... (required params as shown above)
265
+ draft_result_parser: ->(text) { my_custom_draft_parser(text) },
266
+ review_result_parser: ->(text) { my_custom_review_parser(text) }
267
+ )
268
+ ```
243
269
 
244
- result.citations.each do |c|
245
- puts "#{c[:source]}: #{c[:excerpt]}"
270
+ Raise on low confidence:
271
+
272
+ ```ruby
273
+ begin
274
+ result = pipeline.invoke("question")
275
+ rescue Phronomy::LowConfidenceError => e
276
+ puts "Untrusted (confidence #{e.result.confidence}): #{e.result.output}"
277
+ end
278
+ ```
279
+
280
+ ### Agent::Orchestrator — Parallel subagent dispatch
281
+
282
+ ```ruby
283
+ class ResearchOrchestrator < Phronomy::Agent::Orchestrator
284
+ model "gpt-4o"
285
+ instructions "Coordinate research tasks by dispatching to specialised agents."
286
+
287
+ # Each subagent is automatically exposed as an LLM-callable tool.
288
+ subagent :searcher, SearchAgent
289
+ subagent :summarizer, SummaryAgent, on_error: :skip
290
+ end
291
+
292
+ result = ResearchOrchestrator.new.invoke("Research the latest AI news.")
293
+ ```
294
+
295
+ Programmatic parallel dispatch (no LLM loop):
296
+
297
+ ```ruby
298
+ class MyOrchestrator < Phronomy::Agent::Orchestrator
299
+ model "gpt-4o"
300
+ instructions "Orchestrate."
301
+
302
+ def run(query)
303
+ # Heterogeneous agents in parallel
304
+ results = dispatch_parallel(
305
+ {agent: SearchAgent, input: "topic A"},
306
+ {agent: AnalysisAgent, input: query}
307
+ )
308
+
309
+ # Fan-out — same agent, multiple inputs
310
+ translations = fan_out(agent: TranslationAgent, inputs: %w[Hello World])
311
+
312
+ results.map { |r| r[:output] }.join("\n")
313
+ end
246
314
  end
247
315
  ```
248
316
 
@@ -328,18 +396,19 @@ search_tool = Phronomy::Tool::McpTool.from_server(
328
396
 
329
397
  ### Conversation History — passing prior messages
330
398
 
331
- Phronomy does not manage conversation history internally. Instead, the application owns the
332
- message array and passes it in via `config[:messages]`:
399
+ Phronomy does not manage conversation history internally. The application owns the
400
+ message array and passes it in via the `messages:` keyword argument:
333
401
 
334
402
  ```ruby
335
403
  # First turn
336
- result1 = MyAgent.new.invoke("Hello! I'm Alice.", config: { thread_id: "session-1" })
404
+ result1 = MyAgent.new.invoke("Hello! I'm Alice.", thread_id: "session-1")
337
405
  prior_messages = result1[:messages] # Array<RubyLLM::Message>
338
406
 
339
407
  # Second turn — pass prior messages so the agent has context
340
408
  result2 = MyAgent.new.invoke(
341
409
  "What is my name?",
342
- config: { messages: prior_messages, thread_id: "session-1" }
410
+ messages: prior_messages,
411
+ thread_id: "session-1"
343
412
  )
344
413
  puts result2[:output] # => "Your name is Alice."
345
414
  ```
@@ -432,7 +501,7 @@ bundle exec ruby NN_example_name/run.rb
432
501
  | 16 | `16_before_completion_hook/` | Global/class/instance before_completion hooks |
433
502
  | 17 | `17_multi_agent_handoff/` | Hub-and-spoke agent routing via Runner |
434
503
  | 18 | `18_rails_agent_job/` | Rails app with AgentJob + ActionCable streaming |
435
- | 19 | `19_trust_pipeline/` | Trustworthy output via Citation Tracking + Self-Review + Confidence Gate |
504
+ | 19 | `19_trust_pipeline/` | Generator-Verifier pattern with citation tracking, self-review loop and confidence gate |
436
505
 
437
506
  ## Development
438
507