phronomy 0.32.0 → 0.34.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 +139 -0
- data/CONTRIBUTING.md +5 -5
- data/README.md +20 -1
- data/RELEASE_CHECKLIST.md +7 -1
- data/SECURITY.md +1 -1
- data/VERIFY.sh +1 -9
- data/docs/architecture/error-api-review.md +6 -2
- data/docs/architecture/structured-output-and-scope.md +8 -8
- data/docs/architecture/trust-acceptance-followup.md +15 -0
- data/docs/context-policy-budgeting.md +108 -0
- data/docs/decisions/016-semantic-multi-agent-handoff.md +6 -5
- data/docs/examples/shared_state_custom_sharing.rb +145 -0
- data/docs/features.md +4 -2
- data/docs/mcp-client.md +4 -2
- data/docs/migrations/cleanup-audit.md +89 -0
- data/docs/migrations/legacy-format-removal.md +55 -0
- data/docs/migrations/r8-unit6.md +4 -2
- data/docs/migrations/shared-state-multi-agent.md +5 -0
- data/docs/migrations/vector-async-clients.md +6 -1
- data/docs/runtime-and-concurrency.md +36 -0
- data/docs/shared-state-sharing.md +233 -0
- data/lib/phronomy/agent/base.rb +53 -0
- data/lib/phronomy/agent/execution/agent_invocation.rb +0 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +11 -0
- data/lib/phronomy/agent/handoff/transfer_projection.rb +0 -9
- data/lib/phronomy/agent/journal/journal_record.rb +2 -2
- data/lib/phronomy/agent/lifecycle/hosted_invocation.rb +2 -5
- data/lib/phronomy/agent/recovery/recovery_rules.rb +0 -12
- data/lib/phronomy/agent/store.rb +3 -8
- data/lib/phronomy/agent/tool_execution/tool_approval_request.rb +3 -2
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +9 -36
- data/lib/phronomy/context/context_policy.rb +13 -8
- data/lib/phronomy/context/context_policy_input.rb +26 -0
- data/lib/phronomy/context/llm_input_manifest.rb +3 -3
- data/lib/phronomy/engine/runtime/shutdown_result.rb +0 -5
- data/lib/phronomy/execution/execution.rb +0 -11
- data/lib/phronomy/multi_agent/shared_state/binding.rb +44 -0
- data/lib/phronomy/multi_agent/shared_state/member_lifecycle_error.rb +32 -0
- data/lib/phronomy/multi_agent/shared_state.rb +152 -10
- data/lib/phronomy/tool/base.rb +69 -3
- data/lib/phronomy/tool/schema.rb +23 -11
- data/lib/phronomy/version.rb +1 -1
- data/scripts/api_snapshot.rb +6 -3
- data/sig/phronomy/agent.rbs +1 -0
- data/sig/phronomy/context.rbs +3 -0
- data/sig/phronomy/multi_agent.rbs +26 -2
- data/sig/phronomy/tool.rbs +1 -0
- metadata +9 -11
- data/lib/phronomy/execution/scheduler_reentrancy_error.rb +0 -9
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +0 -226
- data/scripts/add_to_h_to_token_doubles.rb +0 -33
- data/scripts/add_to_h_unnamed_doubles.rb +0 -27
- data/scripts/migrate_generator_verifier_result.rb +0 -18
- data/scripts/migrate_spec_agent_definition.rb +0 -108
- data/scripts/migrate_spec_agent_definition_pass2.rb +0 -53
- data/scripts/migrate_spec_inline_pass3.rb +0 -24
- data/sig/phronomy/persistence/migration.rbs +0 -13
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Migrates spec files to add agent_definition to Agent::Base subclasses.
|
|
5
|
-
# - Named classes: inserts after the class declaration line
|
|
6
|
-
# - Anonymous blocks (do...end): inserts after the opening `do`
|
|
7
|
-
# - Inline anonymous ({ ... }): expands to multi-line with agent_definition
|
|
8
|
-
# Safe: skips classes that already have agent_definition
|
|
9
|
-
|
|
10
|
-
require "fileutils"
|
|
11
|
-
|
|
12
|
-
SPEC_DIR = File.expand_path("../spec", __dir__)
|
|
13
|
-
AGENT_BASE_PATTERN = /Phronomy::Agent::Base/
|
|
14
|
-
|
|
15
|
-
def snake_case(class_name)
|
|
16
|
-
# Remove trailing Agent/Tool suffixes, snake_case the name
|
|
17
|
-
name = class_name.split("::").last
|
|
18
|
-
name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
19
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
20
|
-
.downcase
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
counter = 0
|
|
24
|
-
files_modified = 0
|
|
25
|
-
|
|
26
|
-
Dir.glob("#{SPEC_DIR}/**/*.rb").sort.each do |file|
|
|
27
|
-
lines = File.readlines(file, chomp: false)
|
|
28
|
-
new_lines = []
|
|
29
|
-
modified = false
|
|
30
|
-
i = 0
|
|
31
|
-
|
|
32
|
-
while i < lines.length
|
|
33
|
-
line = lines[i]
|
|
34
|
-
|
|
35
|
-
# ── Named class: class FooAgent < Phronomy::Agent::Base ──────────────────
|
|
36
|
-
if line =~ /^(\s*)class\s+(\w+)\s*<\s*(?:::)?Phronomy::Agent::Base\s*$/
|
|
37
|
-
indent = $1
|
|
38
|
-
class_name = $2
|
|
39
|
-
id = snake_case(class_name).sub(/_agent$/, "-agent").tr("_", "-")
|
|
40
|
-
id = "#{id}-agent" unless id.end_with?("-agent")
|
|
41
|
-
new_lines << line
|
|
42
|
-
i += 1
|
|
43
|
-
# Check if agent_definition already present in the class body
|
|
44
|
-
look_ahead = lines[i..]&.take(10) || []
|
|
45
|
-
unless look_ahead.any? { |l| l =~ /agent_definition/ }
|
|
46
|
-
new_lines << "#{indent} agent_definition id: #{id.inspect}, version: 1\n"
|
|
47
|
-
counter += 1
|
|
48
|
-
modified = true
|
|
49
|
-
end
|
|
50
|
-
next
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# ── Anonymous block (do...end): Class.new(Phronomy::Agent::Base) do ─────
|
|
54
|
-
if line =~ /^(\s*)([\w.]*\s*=\s*)?Class\.new\((?:::)?Phronomy::Agent::Base\)\s+do\s*(\|\w+\|)?\s*$/
|
|
55
|
-
indent = $1
|
|
56
|
-
# Check if agent_definition already present
|
|
57
|
-
look_ahead = lines[i + 1..]&.take(10) || []
|
|
58
|
-
new_lines << line
|
|
59
|
-
i += 1
|
|
60
|
-
unless look_ahead.any? { |l| l =~ /agent_definition/ }
|
|
61
|
-
# Derive indentation from the `do` block body (first non-blank line)
|
|
62
|
-
inner = lines[i..]&.take(5)&.find { |l| l.strip.length > 0 } || ""
|
|
63
|
-
inner_indent = inner.match(/^(\s*)/)[1]
|
|
64
|
-
inner_indent = "#{indent} " if inner_indent.strip.length > 0 && inner_indent.length < indent.length + 2
|
|
65
|
-
new_lines << "#{inner_indent}agent_definition id: \"test-agent-#{counter += 1}\", version: 1\n"
|
|
66
|
-
modified = true
|
|
67
|
-
end
|
|
68
|
-
next
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# ── Inline anonymous: Class.new(Phronomy::Agent::Base) { ... } ───────────
|
|
72
|
-
if line =~ /^(\s*)((?:[\w.]*\s*=\s*)?)Class\.new\((?:::)?Phronomy::Agent::Base\)\s*\{(.+)\}\s*$/
|
|
73
|
-
indent = $1
|
|
74
|
-
assignment = $2
|
|
75
|
-
body = $3
|
|
76
|
-
# Skip if agent_definition already present
|
|
77
|
-
if /agent_definition/.match?(body)
|
|
78
|
-
new_lines << line
|
|
79
|
-
else
|
|
80
|
-
id = counter += 1
|
|
81
|
-
definition_line = "agent_definition id: \"test-agent-#{id}\", version: 1;"
|
|
82
|
-
new_lines << "#{indent}#{assignment}Class.new(Phronomy::Agent::Base) do\n"
|
|
83
|
-
new_lines << "#{indent} #{definition_line}\n"
|
|
84
|
-
# Rewrite the original body lines, stripping leading spaces
|
|
85
|
-
body.strip.split(";").each do |stmt|
|
|
86
|
-
stmt = stmt.strip
|
|
87
|
-
next if stmt.empty?
|
|
88
|
-
new_lines << "#{indent} #{stmt}\n"
|
|
89
|
-
end
|
|
90
|
-
new_lines << "#{indent}end\n"
|
|
91
|
-
modified = true
|
|
92
|
-
end
|
|
93
|
-
i += 1
|
|
94
|
-
next
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
new_lines << line
|
|
98
|
-
i += 1
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
if modified
|
|
102
|
-
File.write(file, new_lines.join)
|
|
103
|
-
files_modified += 1
|
|
104
|
-
puts " patched: #{file.sub("#{SPEC_DIR}/", "spec/")}"
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
puts "\nDone: #{counter} agent_definition insertions in #{files_modified} files."
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Second pass: handles patterns missed by the first script
|
|
5
|
-
# - Class.new(Phronomy::Agent::Base) { ... }.new (inline + .new suffix)
|
|
6
|
-
# - Class.new(Phronomy::Agent::Base).new (no block + .new)
|
|
7
|
-
# - { Class.new(Phronomy::Agent::Base) } (no block, inside outer { })
|
|
8
|
-
|
|
9
|
-
require "fileutils"
|
|
10
|
-
|
|
11
|
-
SPEC_DIR = File.expand_path("../spec", __dir__)
|
|
12
|
-
counter = 200
|
|
13
|
-
|
|
14
|
-
files_modified = 0
|
|
15
|
-
|
|
16
|
-
Dir.glob("#{SPEC_DIR}/**/*.rb").sort.each do |file|
|
|
17
|
-
content = File.read(file)
|
|
18
|
-
new_content = content.dup
|
|
19
|
-
|
|
20
|
-
# Pattern A: Class.new(Phronomy::Agent::Base) { body }.new
|
|
21
|
-
new_content = new_content.gsub(
|
|
22
|
-
/Class\.new\(Phronomy::Agent::Base\) \{([^}]*)\}\.new/
|
|
23
|
-
) do
|
|
24
|
-
body = $1
|
|
25
|
-
next $& if body.include?("agent_definition")
|
|
26
|
-
counter += 1
|
|
27
|
-
"Class.new(Phronomy::Agent::Base) { agent_definition id: \"test-agent-#{counter}\", version: 1;#{body}}.new"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Pattern B: Class.new(Phronomy::Agent::Base).new (no block, chained .new)
|
|
31
|
-
new_content = new_content.gsub(
|
|
32
|
-
/Class\.new\(Phronomy::Agent::Base\)\.new\b/
|
|
33
|
-
) do
|
|
34
|
-
counter += 1
|
|
35
|
-
"Class.new(Phronomy::Agent::Base) { agent_definition id: \"test-agent-#{counter}\", version: 1 }.new"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Pattern C: { Class.new(Phronomy::Agent::Base) } (no block, inside outer block)
|
|
39
|
-
new_content = new_content.gsub(
|
|
40
|
-
"{ Class.new(Phronomy::Agent::Base) }"
|
|
41
|
-
) do
|
|
42
|
-
counter += 1
|
|
43
|
-
"{ Class.new(Phronomy::Agent::Base) { agent_definition id: \"test-agent-#{counter}\", version: 1 } }"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
if new_content != content
|
|
47
|
-
File.write(file, new_content)
|
|
48
|
-
files_modified += 1
|
|
49
|
-
puts " patched: #{file.sub("#{SPEC_DIR}/", "spec/")}"
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
puts "\nSecond pass done: #{files_modified} files modified."
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Adds agent_definition to single-line inline anonymous blocks like:
|
|
5
|
-
# Class.new(Phronomy::Agent::Base) { model "test-model" }
|
|
6
|
-
|
|
7
|
-
counter = 300
|
|
8
|
-
files = Dir.glob("spec/**/*.rb").sort
|
|
9
|
-
|
|
10
|
-
files.each do |f|
|
|
11
|
-
content = File.read(f)
|
|
12
|
-
modified = content.gsub(
|
|
13
|
-
/Class\.new\(Phronomy::Agent::Base\) \{ ([^{}]+) \}/
|
|
14
|
-
) do
|
|
15
|
-
body = $1
|
|
16
|
-
next $& if body.include?("agent_definition")
|
|
17
|
-
counter += 1
|
|
18
|
-
"Class.new(Phronomy::Agent::Base) { agent_definition id: \"test-agent-#{counter}\", version: 1; #{body} }"
|
|
19
|
-
end
|
|
20
|
-
if modified != content
|
|
21
|
-
File.write(f, modified)
|
|
22
|
-
puts " patched: #{f}"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module Phronomy
|
|
2
|
-
class Persistence
|
|
3
|
-
module Migration
|
|
4
|
-
module InitialFormatMigration
|
|
5
|
-
def self.agent_root: (Hash[untyped, untyped] hash) -> Storage::DurableRecord
|
|
6
|
-
def self.agent_execution: (Hash[untyped, untyped] hash) -> Storage::DurableRecord
|
|
7
|
-
def self.journal_record: (Hash[untyped, untyped] hash) -> Storage::DurableRecord
|
|
8
|
-
def self.workflow_state: (workflow_instance_id: String, revision: Integer, snapshot: Hash[untyped, untyped]) -> Storage::DurableRecord
|
|
9
|
-
def self.llm_input_manifest: (Hash[untyped, untyped] hash) -> Hash[String, untyped]
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|