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
data/lib/phronomy/tool/schema.rb
CHANGED
|
@@ -43,19 +43,17 @@ module Phronomy
|
|
|
43
43
|
unless @json_schema.is_a?(Hash) && @json_schema["type"] == "object"
|
|
44
44
|
raise ArgumentError, "Tool schema must declare an object"
|
|
45
45
|
end
|
|
46
|
+
@json_schema = Phronomy::Values::Immutable.copy(@json_schema)
|
|
46
47
|
@references = []
|
|
47
48
|
validate_keywords!(@json_schema)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
freeze
|
|
57
|
-
rescue JSONSchemer::InvalidRefPointer, JSONSchemer::InvalidRefResolution => error
|
|
58
|
-
raise ArgumentError, "invalid local Tool schema reference: #{error.message}"
|
|
49
|
+
@references.freeze
|
|
50
|
+
compile_validator!
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Build an independent validator from this immutable Tool definition.
|
|
54
|
+
# @api private
|
|
55
|
+
def for_tool_instance
|
|
56
|
+
dup.compile_validator!
|
|
59
57
|
end
|
|
60
58
|
|
|
61
59
|
# @api public
|
|
@@ -99,6 +97,20 @@ module Phronomy
|
|
|
99
97
|
end
|
|
100
98
|
end
|
|
101
99
|
|
|
100
|
+
protected
|
|
101
|
+
|
|
102
|
+
def compile_validator!
|
|
103
|
+
options = {ref_resolver: ->(uri) { raise ArgumentError, "external Tool schema reference: #{uri}" }}
|
|
104
|
+
unless JSONSchemer.valid_schema?(@json_schema, **options)
|
|
105
|
+
raise ArgumentError, "invalid Tool JSON Schema"
|
|
106
|
+
end
|
|
107
|
+
@validator = JSONSchemer.schema(@json_schema, **options)
|
|
108
|
+
@references.each { |reference| @validator.ref(reference) }
|
|
109
|
+
freeze
|
|
110
|
+
rescue JSONSchemer::InvalidRefPointer, JSONSchemer::InvalidRefResolution => error
|
|
111
|
+
raise ArgumentError, "invalid local Tool schema reference: #{error.message}"
|
|
112
|
+
end
|
|
113
|
+
|
|
102
114
|
private
|
|
103
115
|
|
|
104
116
|
def error_message(error)
|
data/lib/phronomy/version.rb
CHANGED
data/scripts/api_snapshot.rb
CHANGED
|
@@ -106,9 +106,12 @@ def snapshot_entry(klass)
|
|
|
106
106
|
"public_class_methods" => (klass.public_methods(false) - BASELINE_CLASS_METHODS).sort
|
|
107
107
|
}
|
|
108
108
|
else
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
internal_methods = case klass.name
|
|
110
|
+
when "Phronomy::InvocationContext" then %i[__bind_execution __execution_scope]
|
|
111
|
+
when "Phronomy::Tool::Schema" then %i[for_tool_instance]
|
|
112
|
+
else []
|
|
113
|
+
end
|
|
114
|
+
instance_methods = (klass.public_instance_methods - BASELINE_INSTANCE_METHODS - internal_methods).sort
|
|
112
115
|
internal_class_methods = (klass == Phronomy::Storage::AsyncClient) ? %i[submit] : []
|
|
113
116
|
class_methods = (klass.public_methods(false) - BASELINE_CLASS_METHODS - internal_class_methods).sort
|
|
114
117
|
{
|
data/sig/phronomy/agent.rbs
CHANGED
|
@@ -83,6 +83,7 @@ module Phronomy
|
|
|
83
83
|
def self.instructions: (?untyped text) { (untyped) -> untyped } -> untyped
|
|
84
84
|
| (?untyped text) -> untyped
|
|
85
85
|
def self.tools: (?Hash[Class, String?] definitions) -> untyped
|
|
86
|
+
def self.with_tools: (Hash[Class, String?] definitions, id: String, version: Integer) -> singleton(Base)
|
|
86
87
|
def self.tool_aliases: () -> Hash[Class, String]
|
|
87
88
|
def self.provider: (?Symbol name) -> Symbol?
|
|
88
89
|
def self.temperature: (?Float value) -> Float?
|
data/sig/phronomy/context.rbs
CHANGED
|
@@ -110,6 +110,8 @@ module Phronomy
|
|
|
110
110
|
attr_reader previous_manifest: LLMInputManifest?
|
|
111
111
|
attr_reader metadata: Hash[untyped, untyped]
|
|
112
112
|
def initialize: (agent_id: String, ?execution_id: String?, call_sequence: Integer, call_mode: Symbol, ?instruction: Array[InstructionItem], ?knowledge: Array[KnowledgeItem], ?tools: Array[ToolItem], ?conversation: Array[Array[ConversationItem]], token_budget: untyped, ?model_config: Hash[untyped, untyped], previous_manifest: LLMInputManifest?, ?metadata: Hash[untyped, untyped]) -> void
|
|
113
|
+
def input_token_limit: () -> Integer?
|
|
114
|
+
def with_input_token_limit: (Integer limit) -> ContextPolicyInput
|
|
113
115
|
end
|
|
114
116
|
|
|
115
117
|
class ContextPlan
|
|
@@ -124,6 +126,7 @@ module Phronomy
|
|
|
124
126
|
class ContextPolicy
|
|
125
127
|
def call: (ContextPolicyInput input) -> ContextPlan
|
|
126
128
|
|
|
129
|
+
def estimate_tokens: (untyped content) -> Integer
|
|
127
130
|
def instruction_item: (content: untyped, ?role: Symbol, ?kind: Symbol, ?content_format: Symbol?, ?required: bool, ?metadata: Hash[untyped, untyped]) -> ContextPolicyInput::InstructionItem
|
|
128
131
|
def knowledge_item: (content: untyped, ?role: Symbol, ?kind: Symbol, ?content_format: Symbol?, ?required: bool, ?metadata: Hash[untyped, untyped]) -> ContextPolicyInput::KnowledgeItem
|
|
129
132
|
def conversation_item: (content: untyped, role: Symbol, ?kind: Symbol, ?content_format: Symbol?, ?sequence: Integer?, ?required: bool, ?tool_call_id: String?, ?tool_call_ids: Array[String], ?delivery: Symbol, ?metadata: Hash[untyped, untyped]) -> ContextPolicyInput::ConversationItem
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
module Phronomy
|
|
2
2
|
module MultiAgent
|
|
3
3
|
class SharedState
|
|
4
|
+
interface _SharingTools
|
|
5
|
+
def call: (member: singleton(::Phronomy::Agent::Base), cycle: Integer) -> Hash[singleton(::Phronomy::Tool::Base), untyped]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
interface _SharingProvider
|
|
9
|
+
def open: (input: untyped, config: Hash[Symbol, untyped]) { (Binding) -> untyped } -> untyped
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Binding
|
|
13
|
+
def self.new: (store: untyped, tools: _SharingTools) -> instance
|
|
14
|
+
attr_reader store: untyped
|
|
15
|
+
def tool_definitions: (member: singleton(::Phronomy::Agent::Base), cycle: Integer) -> Hash[singleton(::Phronomy::Tool::Base), String?]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class MemberLifecycleError < ::Phronomy::Error
|
|
19
|
+
attr_reader agent: ::Phronomy::Agent::Base
|
|
20
|
+
attr_reader result: untyped
|
|
21
|
+
attr_reader reason: Symbol
|
|
22
|
+
attr_reader primary_error: Exception?
|
|
23
|
+
attr_reader release_error: Exception?
|
|
24
|
+
def self.new: (agent: ::Phronomy::Agent::Base, result: untyped, reason: Symbol, ?primary_error: Exception?, ?release_error: Exception?) -> instance
|
|
25
|
+
end
|
|
26
|
+
|
|
4
27
|
class KnowledgeStore
|
|
5
28
|
def self.new: () -> instance
|
|
6
29
|
def read_all: () -> Array[Hash[Symbol, untyped]]
|
|
@@ -13,8 +36,9 @@ module Phronomy
|
|
|
13
36
|
def self.coordination: (?untyped text) -> untyped
|
|
14
37
|
def self.max_cycles: (?untyped value) -> Integer?
|
|
15
38
|
def self.timeout: (?untyped value) -> Float?
|
|
16
|
-
def self.terminate_when: () ?{ (
|
|
17
|
-
def self.aggregate: () ?{ (
|
|
39
|
+
def self.terminate_when: () ?{ (untyped) -> untyped } -> untyped
|
|
40
|
+
def self.aggregate: () ?{ (untyped) -> untyped } -> untyped
|
|
41
|
+
def self.sharing: (_SharingProvider provider, id: String, version: Integer) -> Hash[Symbol, untyped]
|
|
18
42
|
def invoke: (untyped input, ?config: Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
19
43
|
end
|
|
20
44
|
|
data/sig/phronomy/tool.rbs
CHANGED
|
@@ -55,6 +55,7 @@ module Phronomy
|
|
|
55
55
|
def requires_approval?: () -> untyped
|
|
56
56
|
def tool_origin: () -> Symbol
|
|
57
57
|
def approval_metadata: () -> Hash[untyped, untyped]
|
|
58
|
+
def approval_display: (arguments: Hash[String | Symbol, untyped], facts: Hash[untyped, untyped]) -> { arguments: Hash[String | Symbol, untyped], facts: Hash[untyped, untyped] }
|
|
58
59
|
def execute: (**untyped args) -> untyped
|
|
59
60
|
|
|
60
61
|
private
|
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.34.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-11-
|
|
11
|
+
date: 2026-11-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -257,6 +257,7 @@ files:
|
|
|
257
257
|
- docs/archive/design/historical/06_design_decisions.md
|
|
258
258
|
- docs/async-composition.md
|
|
259
259
|
- docs/changelog/0.14-and-earlier.md
|
|
260
|
+
- docs/context-policy-budgeting.md
|
|
260
261
|
- docs/decisions/001-rubyllm-as-provider-layer.md
|
|
261
262
|
- docs/decisions/002-workflow-context-immutability.md
|
|
262
263
|
- docs/decisions/003-event-loop-singleton.md
|
|
@@ -333,6 +334,7 @@ files:
|
|
|
333
334
|
- docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md
|
|
334
335
|
- docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md
|
|
335
336
|
- docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md
|
|
337
|
+
- docs/examples/shared_state_custom_sharing.rb
|
|
336
338
|
- docs/execution-boundaries-preview.md
|
|
337
339
|
- docs/failure-reason-codes.md
|
|
338
340
|
- docs/features.md
|
|
@@ -343,8 +345,10 @@ files:
|
|
|
343
345
|
- docs/migrations/0.19.md
|
|
344
346
|
- docs/migrations/0.22.md
|
|
345
347
|
- docs/migrations/0.31.md
|
|
348
|
+
- docs/migrations/cleanup-audit.md
|
|
346
349
|
- docs/migrations/durable-semantic-coordination-v2.md
|
|
347
350
|
- docs/migrations/handoff-runner-multi-agent.md
|
|
351
|
+
- docs/migrations/legacy-format-removal.md
|
|
348
352
|
- docs/migrations/neutral-storage-spi.md
|
|
349
353
|
- docs/migrations/parallel-tool-chat-removal.md
|
|
350
354
|
- docs/migrations/persistence-failure-contracts.md
|
|
@@ -376,6 +380,7 @@ files:
|
|
|
376
380
|
- docs/ordered-event-delivery.md
|
|
377
381
|
- docs/persistence-backends.md
|
|
378
382
|
- docs/runtime-and-concurrency.md
|
|
383
|
+
- docs/shared-state-sharing.md
|
|
379
384
|
- docs/workflow-completion.md
|
|
380
385
|
- examples/README.md
|
|
381
386
|
- gemfiles/http_minimum.gemfile
|
|
@@ -558,7 +563,6 @@ files:
|
|
|
558
563
|
- lib/phronomy/execution/runnable.rb
|
|
559
564
|
- lib/phronomy/execution/runtime_shutdown_error.rb
|
|
560
565
|
- lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb
|
|
561
|
-
- lib/phronomy/execution/scheduler_reentrancy_error.rb
|
|
562
566
|
- lib/phronomy/execution/task_result.rb
|
|
563
567
|
- lib/phronomy/execution/timeout_error.rb
|
|
564
568
|
- lib/phronomy/execution/wait_policy.rb
|
|
@@ -616,6 +620,8 @@ files:
|
|
|
616
620
|
- lib/phronomy/multi_agent/reserved_child_admission.rb
|
|
617
621
|
- lib/phronomy/multi_agent/runtime_binding/engine_environment.rb
|
|
618
622
|
- lib/phronomy/multi_agent/shared_state.rb
|
|
623
|
+
- lib/phronomy/multi_agent/shared_state/binding.rb
|
|
624
|
+
- lib/phronomy/multi_agent/shared_state/member_lifecycle_error.rb
|
|
619
625
|
- lib/phronomy/multi_agent/store.rb
|
|
620
626
|
- lib/phronomy/multi_agent/team_busy_error.rb
|
|
621
627
|
- lib/phronomy/multi_agent/team_coordinator.rb
|
|
@@ -631,7 +637,6 @@ files:
|
|
|
631
637
|
- lib/phronomy/output_parser/structured_parser.rb
|
|
632
638
|
- lib/phronomy/persistence/content_repository.rb
|
|
633
639
|
- lib/phronomy/persistence/errors.rb
|
|
634
|
-
- lib/phronomy/persistence/migration/initial_format_migration.rb
|
|
635
640
|
- lib/phronomy/persistence/persistence.rb
|
|
636
641
|
- lib/phronomy/persistence/save_outcome.rb
|
|
637
642
|
- lib/phronomy/persistence/snapshot_comparison.rb
|
|
@@ -744,16 +749,10 @@ files:
|
|
|
744
749
|
- lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb
|
|
745
750
|
- lib/phronomy/workflow/runtime_binding/workflow_task_session.rb
|
|
746
751
|
- lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb
|
|
747
|
-
- scripts/add_to_h_to_token_doubles.rb
|
|
748
|
-
- scripts/add_to_h_unnamed_doubles.rb
|
|
749
752
|
- scripts/api_snapshot.rb
|
|
750
753
|
- scripts/check_api_annotations.rb
|
|
751
754
|
- scripts/check_readme_ruby.rb
|
|
752
755
|
- scripts/check_readme_runnable.rb
|
|
753
|
-
- scripts/migrate_generator_verifier_result.rb
|
|
754
|
-
- scripts/migrate_spec_agent_definition.rb
|
|
755
|
-
- scripts/migrate_spec_agent_definition_pass2.rb
|
|
756
|
-
- scripts/migrate_spec_inline_pass3.rb
|
|
757
756
|
- scripts/run_mutation.sh
|
|
758
757
|
- scripts/storage_spi_snapshot.rb
|
|
759
758
|
- sig/_private/phronomy/agent/settings.rbs
|
|
@@ -815,7 +814,6 @@ files:
|
|
|
815
814
|
- sig/phronomy/multi_agent/team_not_found_error.rbs
|
|
816
815
|
- sig/phronomy/persistence.rbs
|
|
817
816
|
- sig/phronomy/persistence/errors.rbs
|
|
818
|
-
- sig/phronomy/persistence/migration.rbs
|
|
819
817
|
- sig/phronomy/persistence/transaction.rbs
|
|
820
818
|
- sig/phronomy/persistence_composition.rbs
|
|
821
819
|
- sig/phronomy/runtime_composition/configuration.rbs
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "event_loop_reentrancy_error"
|
|
4
|
-
|
|
5
|
-
module Phronomy
|
|
6
|
-
# Backward-compatible error class name for callers that still rescue the old
|
|
7
|
-
# scheduler-oriented exception. New code should use EventLoopReentrancyError.
|
|
8
|
-
class SchedulerReentrancyError < EventLoopReentrancyError; end
|
|
9
|
-
end
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Phronomy
|
|
4
|
-
class Persistence
|
|
5
|
-
module Migration
|
|
6
|
-
# Explicit logical conversion from the pre-S3 unversioned representations
|
|
7
|
-
# present at the ACS-06 fixed base to the initial 0.1 durable formats.
|
|
8
|
-
#
|
|
9
|
-
# This module does not scan a database or write records. A backend-specific
|
|
10
|
-
# migration runner is responsible for physical enumeration, transactions,
|
|
11
|
-
# and replacement. Normal Runtime load never calls these methods.
|
|
12
|
-
#
|
|
13
|
-
# @api public
|
|
14
|
-
module InitialFormatMigration
|
|
15
|
-
PRE_S3_AGENT_ROOT_KEYS = Phronomy::Agent::AgentRoot::ATTRIBUTES.map(&:to_s).freeze
|
|
16
|
-
PRE_S3_AGENT_EXECUTION_KEYS = Phronomy::Agent::AgentExecution::ATTRIBUTES.map(&:to_s).freeze
|
|
17
|
-
PRE_S3_JOURNAL_KEYS = Phronomy::Agent::JournalRecord::ATTRIBUTES.map(&:to_s).freeze
|
|
18
|
-
PRE_S3_LLM_CALL_KEYS = Phronomy::Agent::LLMCallRecord::ATTRIBUTES.map(&:to_s).freeze
|
|
19
|
-
PRE_S3_APPROVAL_REQUIRED_KEYS = %w[id items created_at].freeze
|
|
20
|
-
PRE_S3_APPROVAL_PARENT_KEYS = %w[execution_id agent_invocation_id].freeze
|
|
21
|
-
PRE_S3_APPROVAL_OPTIONAL_KEYS = %w[approved].freeze
|
|
22
|
-
PRE_S3_APPROVAL_ITEM_KEYS = %w[
|
|
23
|
-
tool_invocation_id tool_call_id tool_name arguments facts reason origin metadata
|
|
24
|
-
].freeze
|
|
25
|
-
|
|
26
|
-
module_function
|
|
27
|
-
|
|
28
|
-
def agent_root(hash)
|
|
29
|
-
source = stringify_keys(hash)
|
|
30
|
-
validate_exact_keys!(
|
|
31
|
-
source,
|
|
32
|
-
PRE_S3_AGENT_ROOT_KEYS,
|
|
33
|
-
label: "pre-S3 AgentRoot"
|
|
34
|
-
)
|
|
35
|
-
Phronomy::Agent::Persistence::Codec.encode_agent_root(
|
|
36
|
-
Phronomy::Agent::AgentRoot.from_h(source)
|
|
37
|
-
)
|
|
38
|
-
rescue Phronomy::Storage::SerializationError
|
|
39
|
-
raise
|
|
40
|
-
rescue => error
|
|
41
|
-
migration_error("AgentRoot", error)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def agent_execution(hash)
|
|
45
|
-
source = stringify_keys(hash)
|
|
46
|
-
validate_exact_keys!(
|
|
47
|
-
source,
|
|
48
|
-
PRE_S3_AGENT_EXECUTION_KEYS,
|
|
49
|
-
label: "pre-S3 AgentExecution"
|
|
50
|
-
)
|
|
51
|
-
source["working_records"] = Array(source.fetch("working_records")).map.with_index do |record, index|
|
|
52
|
-
normalize_legacy_journal_record(
|
|
53
|
-
record,
|
|
54
|
-
label: "pre-S3 AgentExecution working_records[#{index}]"
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
source["llm_calls"] = Array(source.fetch("llm_calls")).map.with_index do |call, index|
|
|
58
|
-
normalized = stringify_keys(call)
|
|
59
|
-
validate_exact_keys!(
|
|
60
|
-
normalized,
|
|
61
|
-
PRE_S3_LLM_CALL_KEYS,
|
|
62
|
-
label: "pre-S3 AgentExecution llm_calls[#{index}]"
|
|
63
|
-
)
|
|
64
|
-
normalized
|
|
65
|
-
end
|
|
66
|
-
source["approval_request"] = normalize_legacy_approval_request(
|
|
67
|
-
source["approval_request"],
|
|
68
|
-
execution_id: source.fetch("execution_id")
|
|
69
|
-
)
|
|
70
|
-
execution = Phronomy::Agent::AgentExecution.from_h(source)
|
|
71
|
-
Phronomy::Agent::Persistence::Codec.encode_agent_execution(execution)
|
|
72
|
-
rescue Phronomy::Storage::SerializationError
|
|
73
|
-
raise
|
|
74
|
-
rescue => error
|
|
75
|
-
migration_error("AgentExecution", error)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def journal_record(hash)
|
|
79
|
-
source = normalize_legacy_journal_record(hash, label: "pre-S3 JournalRecord")
|
|
80
|
-
Phronomy::Agent::Persistence::Codec.encode_journal_record(
|
|
81
|
-
Phronomy::Agent::JournalRecord.from_h(source)
|
|
82
|
-
)
|
|
83
|
-
rescue Phronomy::Storage::SerializationError
|
|
84
|
-
raise
|
|
85
|
-
rescue => error
|
|
86
|
-
migration_error("JournalRecord", error)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def workflow_state(workflow_instance_id:, revision:, snapshot:)
|
|
90
|
-
Phronomy::Workflow::Persistence::Codec.encode_workflow_state(
|
|
91
|
-
workflow_instance_id: workflow_instance_id,
|
|
92
|
-
workflow_revision: Integer(revision),
|
|
93
|
-
snapshot: snapshot
|
|
94
|
-
)
|
|
95
|
-
rescue Phronomy::Storage::SerializationError
|
|
96
|
-
raise
|
|
97
|
-
rescue => error
|
|
98
|
-
migration_error("Workflow state", error)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# LLMInputManifest is a ContentStore codec boundary, not a
|
|
102
|
-
# Storage::DurableRecord. Its pre-CG-07 integer version 1 is migrated
|
|
103
|
-
# explicitly to the pre-1.0 string version "0.1".
|
|
104
|
-
def llm_input_manifest(hash)
|
|
105
|
-
source = stringify_keys(hash)
|
|
106
|
-
old_version = source.fetch("version")
|
|
107
|
-
unless old_version == 1 || old_version == "1"
|
|
108
|
-
raise Phronomy::Storage::SerializationError,
|
|
109
|
-
"unsupported pre-S3 LLMInputManifest version: #{old_version.inspect}"
|
|
110
|
-
end
|
|
111
|
-
source["version"] = Phronomy::Context::LLMInputManifest::VERSION
|
|
112
|
-
Phronomy::Context::LLMInputManifest.from_h(source).to_h
|
|
113
|
-
rescue Phronomy::Storage::SerializationError
|
|
114
|
-
raise
|
|
115
|
-
rescue => error
|
|
116
|
-
migration_error("LLMInputManifest", error)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def normalize_legacy_journal_record(hash, label:)
|
|
120
|
-
source = stringify_keys(hash)
|
|
121
|
-
validate_allowed_keys!(
|
|
122
|
-
source,
|
|
123
|
-
required_keys: PRE_S3_JOURNAL_KEYS,
|
|
124
|
-
optional_keys: ["correlation_id"],
|
|
125
|
-
label: label
|
|
126
|
-
)
|
|
127
|
-
source.delete("correlation_id")
|
|
128
|
-
source
|
|
129
|
-
end
|
|
130
|
-
private_class_method :normalize_legacy_journal_record
|
|
131
|
-
|
|
132
|
-
def normalize_legacy_approval_request(request, execution_id:)
|
|
133
|
-
return nil unless request
|
|
134
|
-
|
|
135
|
-
source = stringify_keys(request)
|
|
136
|
-
validate_allowed_keys!(
|
|
137
|
-
source,
|
|
138
|
-
required_keys: PRE_S3_APPROVAL_REQUIRED_KEYS,
|
|
139
|
-
optional_keys: PRE_S3_APPROVAL_PARENT_KEYS + PRE_S3_APPROVAL_OPTIONAL_KEYS,
|
|
140
|
-
label: "pre-S3 approval_request"
|
|
141
|
-
)
|
|
142
|
-
parents = PRE_S3_APPROVAL_PARENT_KEYS.select { |key| source.key?(key) }
|
|
143
|
-
unless parents.length == 1
|
|
144
|
-
raise Phronomy::Storage::SerializationError,
|
|
145
|
-
"pre-S3 approval_request must contain exactly one parent identity, got #{parents.inspect}"
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
items = source.fetch("items")
|
|
149
|
-
unless items.is_a?(Array) && !items.empty?
|
|
150
|
-
raise Phronomy::Storage::SerializationError,
|
|
151
|
-
"pre-S3 approval_request items must be a non-empty Array"
|
|
152
|
-
end
|
|
153
|
-
source["items"] = items.map.with_index do |item, index|
|
|
154
|
-
normalized = stringify_keys(item)
|
|
155
|
-
validate_exact_keys!(
|
|
156
|
-
normalized,
|
|
157
|
-
PRE_S3_APPROVAL_ITEM_KEYS,
|
|
158
|
-
label: "pre-S3 approval_request items[#{index}]"
|
|
159
|
-
)
|
|
160
|
-
normalized
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
if source.key?("agent_invocation_id")
|
|
164
|
-
source.delete("agent_invocation_id")
|
|
165
|
-
source["execution_id"] = execution_id.to_s
|
|
166
|
-
elsif source.fetch("execution_id").to_s != execution_id.to_s
|
|
167
|
-
raise Phronomy::Storage::SerializationError,
|
|
168
|
-
"pre-S3 approval_request execution_id does not match AgentExecution"
|
|
169
|
-
end
|
|
170
|
-
source
|
|
171
|
-
end
|
|
172
|
-
private_class_method :normalize_legacy_approval_request
|
|
173
|
-
|
|
174
|
-
def validate_allowed_keys!(hash, required_keys:, optional_keys:, label:)
|
|
175
|
-
actual = hash.keys.sort
|
|
176
|
-
missing = required_keys.sort - actual
|
|
177
|
-
unknown = actual - (required_keys + optional_keys).sort
|
|
178
|
-
return hash if missing.empty? && unknown.empty?
|
|
179
|
-
|
|
180
|
-
details = []
|
|
181
|
-
details << "missing=#{missing.inspect}" unless missing.empty?
|
|
182
|
-
details << "unknown=#{unknown.inspect}" unless unknown.empty?
|
|
183
|
-
raise Phronomy::Storage::SerializationError,
|
|
184
|
-
"#{label} schema mismatch (#{details.join(", ")})"
|
|
185
|
-
end
|
|
186
|
-
private_class_method :validate_allowed_keys!
|
|
187
|
-
|
|
188
|
-
def validate_exact_keys!(hash, expected_keys, label:)
|
|
189
|
-
validate_allowed_keys!(
|
|
190
|
-
hash,
|
|
191
|
-
required_keys: expected_keys,
|
|
192
|
-
optional_keys: [],
|
|
193
|
-
label: label
|
|
194
|
-
)
|
|
195
|
-
end
|
|
196
|
-
private_class_method :validate_exact_keys!
|
|
197
|
-
|
|
198
|
-
def stringify_keys(hash)
|
|
199
|
-
unless hash.is_a?(Hash)
|
|
200
|
-
raise Phronomy::Storage::SerializationError,
|
|
201
|
-
"migration input must be a Hash"
|
|
202
|
-
end
|
|
203
|
-
hash.each_with_object({}) do |(key, value), result|
|
|
204
|
-
unless key.is_a?(String) || key.is_a?(Symbol)
|
|
205
|
-
raise Phronomy::Storage::SerializationError,
|
|
206
|
-
"migration key must be String or Symbol, got #{key.class}"
|
|
207
|
-
end
|
|
208
|
-
string_key = key.to_s
|
|
209
|
-
if result.key?(string_key)
|
|
210
|
-
raise Phronomy::Storage::SerializationError,
|
|
211
|
-
"duplicate migration key after normalization: #{string_key.inspect}"
|
|
212
|
-
end
|
|
213
|
-
result[string_key] = value
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
private_class_method :stringify_keys
|
|
217
|
-
|
|
218
|
-
def migration_error(label, error)
|
|
219
|
-
raise Phronomy::Storage::SerializationError,
|
|
220
|
-
"cannot migrate pre-S3 #{label}: #{error.class}: #{error.message}"
|
|
221
|
-
end
|
|
222
|
-
private_class_method :migration_error
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Adds to_h to all Tokens-like doubles so ExecutionCoordinator can serialize usage.
|
|
5
|
-
|
|
6
|
-
files = Dir.glob("spec/**/*.rb").sort
|
|
7
|
-
|
|
8
|
-
total = 0
|
|
9
|
-
files.each do |f|
|
|
10
|
-
content = File.read(f)
|
|
11
|
-
modified = content.gsub(
|
|
12
|
-
/double\(("[^"]+"),\s*(input: \d+, output: \d+, cached: \d+, cache_creation: \d+)\)/
|
|
13
|
-
) do
|
|
14
|
-
name = $1
|
|
15
|
-
attrs = $2
|
|
16
|
-
next $& if $&.include?("to_h")
|
|
17
|
-
|
|
18
|
-
h_entries = attrs.split(",").map(&:strip).map do |pair|
|
|
19
|
-
k, v = pair.split(":").map(&:strip)
|
|
20
|
-
"\"#{k}\" => #{v}"
|
|
21
|
-
end.join(", ")
|
|
22
|
-
|
|
23
|
-
total += 1
|
|
24
|
-
"double(#{name}, #{attrs}, to_h: {#{h_entries}})"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
if modified != content
|
|
28
|
-
File.write(f, modified)
|
|
29
|
-
puts " patched: #{f}"
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
puts "\nAdded to_h to #{total} Tokens doubles."
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Adds to_h to unnamed (no-string-name) Tokens doubles like double(input: 5, ...)
|
|
5
|
-
|
|
6
|
-
files = Dir.glob("spec/**/*.rb").sort
|
|
7
|
-
|
|
8
|
-
total = 0
|
|
9
|
-
files.each do |f|
|
|
10
|
-
content = File.read(f)
|
|
11
|
-
modified = content.gsub(
|
|
12
|
-
/double\((input: (\d+), output: (\d+), cached: (\d+), cache_creation: (\d+))\)/
|
|
13
|
-
) do
|
|
14
|
-
attrs, a, b, c, d = $1, $2, $3, $4, $5
|
|
15
|
-
next $& if $&.include?("to_h")
|
|
16
|
-
|
|
17
|
-
total += 1
|
|
18
|
-
"double(#{attrs}, to_h: {\"input\" => #{a}, \"output\" => #{b}, \"cached\" => #{c}, \"cache_creation\" => #{d}})"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
if modified != content
|
|
22
|
-
File.write(f, modified)
|
|
23
|
-
puts " patched: #{f}"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
puts "\nAdded to_h to #{total} unnamed Tokens doubles."
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Explicit one-time conversion of a pre-structured-output Result JSON object.
|
|
5
|
-
# Never infer old formats in the runtime reader; never overwrite the source.
|
|
6
|
-
require_relative "../lib/phronomy"
|
|
7
|
-
|
|
8
|
-
abort "Usage: ruby scripts/migrate_generator_verifier_result.rb OLD.json NEW.json" unless ARGV.length == 2
|
|
9
|
-
source, destination = ARGV
|
|
10
|
-
value = JSON.parse(File.read(source), allow_duplicate_key: false, allow_nan: false,
|
|
11
|
-
allow_comments: false, allow_invalid_escape: false, allow_control_characters: false)
|
|
12
|
-
abort "Expected an old Result object without failure" unless value.is_a?(Hash) && !value.key?("failure")
|
|
13
|
-
value["failure"] = nil
|
|
14
|
-
result = Phronomy::GeneratorVerifier::Result.from_h(value)
|
|
15
|
-
File.open(destination, File::WRONLY | File::CREAT | File::EXCL) do |file|
|
|
16
|
-
file.write(JSON.pretty_generate(result.to_h))
|
|
17
|
-
file.write("\n")
|
|
18
|
-
end
|