smith-agents 0.4.5 → 0.6.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 +264 -0
- data/README.md +191 -4
- data/docs/CONFIGURATION.md +4 -1
- data/docs/PATTERNS.md +7 -0
- data/docs/PERSISTENCE.md +347 -25
- data/lib/smith/agent/lifecycle.rb +19 -10
- data/lib/smith/agent/registry/execution_binding_capture.rb +26 -0
- data/lib/smith/agent/registry/mutation_boundary.rb +29 -0
- data/lib/smith/agent/registry.rb +8 -0
- data/lib/smith/agent.rb +37 -2
- data/lib/smith/budget/amount_contract.rb +67 -0
- data/lib/smith/budget/amount_representation.rb +43 -0
- data/lib/smith/budget/decimal_context.rb +18 -0
- data/lib/smith/budget/ledger.rb +110 -18
- data/lib/smith/budget/ledger_publication.rb +60 -0
- data/lib/smith/budget/ledger_state.rb +21 -0
- data/lib/smith/budget/ledger_state_transition.rb +72 -0
- data/lib/smith/budget/public_state_validator.rb +25 -0
- data/lib/smith/budget/reservation.rb +20 -0
- data/lib/smith/budget/reservation_contract.rb +34 -0
- data/lib/smith/context/observation_masking.rb +3 -1
- data/lib/smith/context/state_injection.rb +1 -1
- data/lib/smith/doctor/checks/persistence_capabilities.rb +18 -4
- data/lib/smith/error.rb +5 -0
- data/lib/smith/errors.rb +10 -0
- data/lib/smith/exponential_backoff.rb +128 -0
- data/lib/smith/persistence_adapters/active_record_exact_predicate.rb +43 -0
- data/lib/smith/persistence_adapters/active_record_exact_store.rb +62 -0
- data/lib/smith/persistence_adapters/active_record_exact_write.rb +40 -0
- data/lib/smith/persistence_adapters/active_record_store.rb +7 -4
- data/lib/smith/persistence_adapters/cache_store.rb +1 -0
- data/lib/smith/persistence_adapters/memory.rb +16 -1
- data/lib/smith/persistence_adapters/redis_client_access.rb +38 -0
- data/lib/smith/persistence_adapters/redis_exact_write.rb +44 -0
- data/lib/smith/persistence_adapters/redis_store.rb +28 -11
- data/lib/smith/persistence_adapters/retry.rb +22 -10
- data/lib/smith/persistence_adapters.rb +21 -18
- data/lib/smith/persistence_payload_conflict.rb +12 -0
- data/lib/smith/tool/budget_enforcement.rb +2 -2
- data/lib/smith/types.rb +1 -0
- data/lib/smith/version.rb +2 -1
- data/lib/smith/workflow/branch_env.rb +1 -1
- data/lib/smith/workflow/budget_integration.rb +21 -11
- data/lib/smith/workflow/composite/branch.rb +93 -0
- data/lib/smith/workflow/composite/branch_budget_contract.rb +41 -0
- data/lib/smith/workflow/composite/branch_contract.rb +102 -0
- data/lib/smith/workflow/composite/branch_execution.rb +124 -0
- data/lib/smith/workflow/composite/branch_failure.rb +91 -0
- data/lib/smith/workflow/composite/branch_outcome.rb +108 -0
- data/lib/smith/workflow/composite/budget_allocator.rb +78 -0
- data/lib/smith/workflow/composite/budget_math.rb +51 -0
- data/lib/smith/workflow/composite/contract.rb +100 -0
- data/lib/smith/workflow/composite/effects.rb +140 -0
- data/lib/smith/workflow/composite/effects_application.rb +36 -0
- data/lib/smith/workflow/composite/effects_baseline.rb +36 -0
- data/lib/smith/workflow/composite/effects_preflight.rb +102 -0
- data/lib/smith/workflow/composite/encoded_value_budget.rb +36 -0
- data/lib/smith/workflow/composite/enums.rb +27 -0
- data/lib/smith/workflow/composite/error.rb +54 -0
- data/lib/smith/workflow/composite/error_evidence.rb +61 -0
- data/lib/smith/workflow/composite/execution_contract.rb +73 -0
- data/lib/smith/workflow/composite/fanout_branch_contract.rb +61 -0
- data/lib/smith/workflow/composite/input.rb +53 -0
- data/lib/smith/workflow/composite/outcome_accumulator.rb +131 -0
- data/lib/smith/workflow/composite/outcome_set.rb +23 -0
- data/lib/smith/workflow/composite/payload.rb +128 -0
- data/lib/smith/workflow/composite/payload_digest.rb +28 -0
- data/lib/smith/workflow/composite/plan.rb +130 -0
- data/lib/smith/workflow/composite/plan_integrity.rb +52 -0
- data/lib/smith/workflow/composite/planner.rb +53 -0
- data/lib/smith/workflow/composite/preparation.rb +27 -0
- data/lib/smith/workflow/composite/reducer.rb +133 -0
- data/lib/smith/workflow/composite/reduction.rb +31 -0
- data/lib/smith/workflow/composite/value_budget.rb +90 -0
- data/lib/smith/workflow/composite_branch_execution_authorization.rb +52 -0
- data/lib/smith/workflow/deadline_enforcement.rb +22 -5
- data/lib/smith/workflow/definition_identity/class_methods.rb +48 -0
- data/lib/smith/workflow/definition_identity.rb +25 -0
- data/lib/smith/workflow/deterministic_step.rb +2 -2
- data/lib/smith/workflow/dsl.rb +73 -5
- data/lib/smith/workflow/durability.rb +1 -1
- data/lib/smith/workflow/evaluator_optimizer.rb +7 -11
- data/lib/smith/workflow/execution.rb +28 -30
- data/lib/smith/workflow/execution_binding_resolution.rb +16 -0
- data/lib/smith/workflow/execution_result_snapshot.rb +118 -0
- data/lib/smith/workflow/fanout_execution.rb +20 -19
- data/lib/smith/workflow/graph/diagnostic.rb +27 -1
- data/lib/smith/workflow/graph/diagnostic_path.rb +24 -0
- data/lib/smith/workflow/graph/execution_successors.rb +65 -0
- data/lib/smith/workflow/graph/identifier_projection.rb +13 -0
- data/lib/smith/workflow/graph/metrics.rb +1 -3
- data/lib/smith/workflow/graph/nested_readiness_diagnostics.rb +15 -16
- data/lib/smith/workflow/graph/optimization_contract.rb +2 -2
- data/lib/smith/workflow/graph/orchestration_contract.rb +3 -3
- data/lib/smith/workflow/graph/reachability.rb +19 -31
- data/lib/smith/workflow/graph/reachability_diagnostics.rb +17 -1
- data/lib/smith/workflow/graph/retry_policy_diagnostic.rb +36 -0
- data/lib/smith/workflow/graph/runtime_binding_diagnostics.rb +2 -2
- data/lib/smith/workflow/graph/runtime_readiness.rb +3 -44
- data/lib/smith/workflow/graph/runtime_readiness_metrics.rb +2 -2
- data/lib/smith/workflow/graph/runtime_readiness_report_builder.rb +47 -0
- data/lib/smith/workflow/graph/runtime_readiness_traversal.rb +108 -0
- data/lib/smith/workflow/graph/state_diagnostics.rb +2 -2
- data/lib/smith/workflow/graph/transition_contract.rb +47 -0
- data/lib/smith/workflow/graph/transition_contract_attributes.rb +73 -0
- data/lib/smith/workflow/graph/transition_contract_configurations.rb +100 -0
- data/lib/smith/workflow/graph/transition_diagnostics.rb +54 -12
- data/lib/smith/workflow/graph/transition_optimization_configuration.rb +62 -0
- data/lib/smith/workflow/graph/transition_snapshot.rb +4 -1
- data/lib/smith/workflow/graph/validator.rb +1 -1
- data/lib/smith/workflow/graph.rb +62 -4
- data/lib/smith/workflow/guardrail_integration.rb +23 -9
- data/lib/smith/workflow/identifier.rb +24 -0
- data/lib/smith/workflow/message_admission.rb +40 -0
- data/lib/smith/workflow/message_admission_boundary.rb +22 -0
- data/lib/smith/workflow/message_batch.rb +60 -0
- data/lib/smith/workflow/message_value_normalizer.rb +134 -0
- data/lib/smith/workflow/nested_execution.rb +10 -0
- data/lib/smith/workflow/orchestrator_worker.rb +3 -7
- data/lib/smith/workflow/parallel/cancellation_signal.rb +14 -5
- data/lib/smith/workflow/parallel/execution_context.rb +113 -0
- data/lib/smith/workflow/parallel/nested_execution.rb +124 -0
- data/lib/smith/workflow/parallel/root_execution.rb +91 -0
- data/lib/smith/workflow/parallel.rb +19 -22
- data/lib/smith/workflow/parallel_agent_binding.rb +24 -0
- data/lib/smith/workflow/parallel_execution.rb +46 -14
- data/lib/smith/workflow/persistence.rb +37 -8
- data/lib/smith/workflow/prepared_branch_execution.rb +31 -0
- data/lib/smith/workflow/prepared_step.rb +122 -0
- data/lib/smith/workflow/prepared_step_dispatch.rb +88 -0
- data/lib/smith/workflow/prepared_step_execution_authorization.rb +101 -0
- data/lib/smith/workflow/prepared_step_execution_result.rb +49 -0
- data/lib/smith/workflow/prepared_step_execution_scope.rb +111 -0
- data/lib/smith/workflow/prepared_step_recovery.rb +38 -0
- data/lib/smith/workflow/process_local.rb +33 -0
- data/lib/smith/workflow/retry_execution.rb +20 -11
- data/lib/smith/workflow/split_step_persistence/boundary.rb +35 -22
- data/lib/smith/workflow/split_step_persistence/boundary_reset.rb +50 -0
- data/lib/smith/workflow/split_step_persistence/canonical_payload_digest.rb +55 -0
- data/lib/smith/workflow/split_step_persistence/checkpoint.rb +3 -5
- data/lib/smith/workflow/split_step_persistence/composite_branch_authorization.rb +99 -0
- data/lib/smith/workflow/split_step_persistence/composite_branch_effects.rb +41 -0
- data/lib/smith/workflow/split_step_persistence/composite_branch_execution.rb +95 -0
- data/lib/smith/workflow/split_step_persistence/composite_branch_outcome.rb +36 -0
- data/lib/smith/workflow/split_step_persistence/composite_execution.rb +39 -0
- data/lib/smith/workflow/split_step_persistence/composite_preparation.rb +57 -0
- data/lib/smith/workflow/split_step_persistence/composite_reduction_execution.rb +122 -0
- data/lib/smith/workflow/split_step_persistence/definition_boundary.rb +19 -0
- data/lib/smith/workflow/split_step_persistence/dispatch_boundary.rb +16 -0
- data/lib/smith/workflow/split_step_persistence/dispatch_claim.rb +118 -0
- data/lib/smith/workflow/split_step_persistence/dispatch_confirmation.rb +70 -0
- data/lib/smith/workflow/split_step_persistence/dispatch_verification.rb +35 -0
- data/lib/smith/workflow/split_step_persistence/execution.rb +20 -64
- data/lib/smith/workflow/split_step_persistence/execution_authorization.rb +109 -0
- data/lib/smith/workflow/split_step_persistence/execution_authorization_issuance.rb +57 -0
- data/lib/smith/workflow/split_step_persistence/execution_binding_collector.rb +95 -0
- data/lib/smith/workflow/split_step_persistence/execution_binding_snapshot.rb +109 -0
- data/lib/smith/workflow/split_step_persistence/execution_lifecycle.rb +96 -0
- data/lib/smith/workflow/split_step_persistence/execution_result_capture.rb +48 -0
- data/lib/smith/workflow/split_step_persistence/execution_verification.rb +77 -0
- data/lib/smith/workflow/split_step_persistence/execution_workflow_snapshot.rb +77 -0
- data/lib/smith/workflow/split_step_persistence/inheritance.rb +3 -1
- data/lib/smith/workflow/split_step_persistence/payloads.rb +7 -3
- data/lib/smith/workflow/split_step_persistence/preparation.rb +30 -2
- data/lib/smith/workflow/split_step_persistence/preparation_claim.rb +38 -12
- data/lib/smith/workflow/split_step_persistence/preparation_payload.rb +25 -0
- data/lib/smith/workflow/split_step_persistence/preparation_recovery.rb +10 -2
- data/lib/smith/workflow/split_step_persistence/recovery.rb +125 -0
- data/lib/smith/workflow/split_step_persistence/recovery_boundary.rb +56 -0
- data/lib/smith/workflow/split_step_persistence/recovery_class_methods.rb +14 -0
- data/lib/smith/workflow/split_step_persistence/replace_exact_signature.rb +46 -0
- data/lib/smith/workflow/split_step_persistence/restart_safe_adapter.rb +42 -0
- data/lib/smith/workflow/split_step_persistence/subclass_boundary.rb +66 -0
- data/lib/smith/workflow/split_step_persistence/transaction_identity.rb +45 -0
- data/lib/smith/workflow/split_step_persistence.rb +50 -0
- data/lib/smith/workflow/step_completion.rb +31 -0
- data/lib/smith/workflow/step_context.rb +46 -0
- data/lib/smith/workflow/string_snapshot.rb +25 -0
- data/lib/smith/workflow/thread_context_snapshot.rb +103 -0
- data/lib/smith/workflow/transition.rb +137 -133
- data/lib/smith/workflow/transition_actionability.rb +22 -0
- data/lib/smith/workflow.rb +64 -18
- data/lib/smith.rb +44 -2
- data/sig/smith.rbs +1 -0
- metadata +155 -19
|
@@ -4,17 +4,46 @@ require "digest"
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "securerandom"
|
|
6
6
|
|
|
7
|
+
require_relative "prepared_step"
|
|
8
|
+
require_relative "prepared_step_dispatch"
|
|
9
|
+
require_relative "prepared_step_execution_authorization"
|
|
10
|
+
require_relative "prepared_step_execution_result"
|
|
11
|
+
require_relative "prepared_step_recovery"
|
|
7
12
|
require_relative "split_step_persistence/subclass_boundary"
|
|
8
13
|
require_relative "split_step_persistence/inheritance"
|
|
14
|
+
require_relative "split_step_persistence/recovery_class_methods"
|
|
9
15
|
require_relative "split_step_persistence/transition_contract_structured_values"
|
|
10
16
|
require_relative "split_step_persistence/transition_contract_signature"
|
|
11
17
|
require_relative "split_step_persistence/transition_contract_freezer"
|
|
12
18
|
require_relative "split_step_persistence/transition_contract"
|
|
19
|
+
require_relative "split_step_persistence/transaction_identity"
|
|
20
|
+
require_relative "split_step_persistence/canonical_payload_digest"
|
|
21
|
+
require_relative "split_step_persistence/definition_boundary"
|
|
13
22
|
require_relative "split_step_persistence/boundary"
|
|
23
|
+
require_relative "split_step_persistence/boundary_reset"
|
|
14
24
|
require_relative "split_step_persistence/state_snapshot"
|
|
15
25
|
require_relative "split_step_persistence/preparation_claim"
|
|
16
26
|
require_relative "split_step_persistence/preparation_recovery"
|
|
17
27
|
require_relative "split_step_persistence/preparation"
|
|
28
|
+
require_relative "split_step_persistence/restart_safe_adapter"
|
|
29
|
+
require_relative "split_step_persistence/recovery"
|
|
30
|
+
require_relative "split_step_persistence/recovery_boundary"
|
|
31
|
+
require_relative "split_step_persistence/preparation_payload"
|
|
32
|
+
require_relative "split_step_persistence/dispatch_boundary"
|
|
33
|
+
require_relative "split_step_persistence/dispatch_claim"
|
|
34
|
+
require_relative "split_step_persistence/dispatch_verification"
|
|
35
|
+
require_relative "split_step_persistence/dispatch_confirmation"
|
|
36
|
+
require_relative "split_step_persistence/execution_verification"
|
|
37
|
+
require_relative "split_step_persistence/execution_binding_snapshot"
|
|
38
|
+
require_relative "split_step_persistence/execution_authorization"
|
|
39
|
+
require_relative "split_step_persistence/execution_authorization_issuance"
|
|
40
|
+
require_relative "split_step_persistence/execution_result_capture"
|
|
41
|
+
require_relative "split_step_persistence/execution_lifecycle"
|
|
42
|
+
require_relative "split_step_persistence/composite_preparation"
|
|
43
|
+
require_relative "split_step_persistence/composite_branch_authorization"
|
|
44
|
+
require_relative "split_step_persistence/composite_branch_execution"
|
|
45
|
+
require_relative "split_step_persistence/composite_reduction_execution"
|
|
46
|
+
require_relative "split_step_persistence/composite_execution"
|
|
18
47
|
require_relative "split_step_persistence/execution"
|
|
19
48
|
require_relative "split_step_persistence/checkpoint_state"
|
|
20
49
|
require_relative "split_step_persistence/checkpoint"
|
|
@@ -27,13 +56,34 @@ module Smith
|
|
|
27
56
|
|
|
28
57
|
def self.prepended(base)
|
|
29
58
|
base.singleton_class.prepend(Inheritance)
|
|
59
|
+
base.extend(RecoveryClassMethods)
|
|
30
60
|
end
|
|
31
61
|
|
|
32
62
|
include Boundary
|
|
63
|
+
include BoundaryReset
|
|
64
|
+
include DefinitionBoundary
|
|
33
65
|
include StateSnapshot
|
|
34
66
|
include PreparationClaim
|
|
35
67
|
include PreparationRecovery
|
|
36
68
|
include Preparation
|
|
69
|
+
include RestartSafeAdapter
|
|
70
|
+
include Recovery
|
|
71
|
+
include RecoveryBoundary
|
|
72
|
+
include PreparationPayload
|
|
73
|
+
include DispatchBoundary
|
|
74
|
+
include DispatchClaim
|
|
75
|
+
include DispatchVerification
|
|
76
|
+
include DispatchConfirmation
|
|
77
|
+
include ExecutionVerification
|
|
78
|
+
include ExecutionAuthorization
|
|
79
|
+
include ExecutionAuthorizationIssuance
|
|
80
|
+
include ExecutionResultCapture
|
|
81
|
+
include ExecutionLifecycle
|
|
82
|
+
include CompositePreparation
|
|
83
|
+
include CompositeBranchAuthorization
|
|
84
|
+
include CompositeBranchExecution
|
|
85
|
+
include CompositeReductionExecution
|
|
86
|
+
include CompositeExecution
|
|
37
87
|
include Execution
|
|
38
88
|
include CheckpointState
|
|
39
89
|
include Checkpoint
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smith
|
|
4
|
+
class Workflow
|
|
5
|
+
module StepCompletion
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def complete_step(transition, output)
|
|
9
|
+
step = { transition: transition.name, from: transition.from, to: transition.to, output: output }
|
|
10
|
+
result = SplitStepPersistence
|
|
11
|
+
.instance_method(:prepare_split_step_execution_result)
|
|
12
|
+
.bind_call(self, step)
|
|
13
|
+
StepCompletion.instance_method(:append_accepted_output).bind_call(self, output)
|
|
14
|
+
SplitStepPersistence
|
|
15
|
+
.instance_method(:commit_split_step_execution_result!)
|
|
16
|
+
.bind_call(self, result)
|
|
17
|
+
@state = transition.to
|
|
18
|
+
@next_transition_name = @router_next_transition || transition.success_transition
|
|
19
|
+
@router_next_transition = nil
|
|
20
|
+
emit_step_completed(transition, output)
|
|
21
|
+
step
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def append_accepted_output(output)
|
|
25
|
+
return unless @session_messages && !output.nil?
|
|
26
|
+
|
|
27
|
+
@session_messages << { role: :assistant, content: output }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "thread_context_snapshot"
|
|
4
|
+
|
|
5
|
+
module Smith
|
|
6
|
+
class Workflow
|
|
7
|
+
module StepContext
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def with_step_context(transition, &block)
|
|
11
|
+
ThreadContextSnapshot.new.around do
|
|
12
|
+
setup_step_context
|
|
13
|
+
Thread.handle_interrupt(Object => :immediate, &block)
|
|
14
|
+
rescue StandardError => e
|
|
15
|
+
@outcome = nil
|
|
16
|
+
GuardrailIntegration.instance_method(:handle_step_failure).bind_call(self, transition, e)
|
|
17
|
+
ensure
|
|
18
|
+
teardown_step_context
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def within_raw_step_context(&block)
|
|
23
|
+
ThreadContextSnapshot.new.around do
|
|
24
|
+
setup_step_context
|
|
25
|
+
Thread.handle_interrupt(Object => :immediate, &block)
|
|
26
|
+
ensure
|
|
27
|
+
teardown_step_context
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def setup_step_context
|
|
32
|
+
Tool.current_deadline = wall_clock_deadline
|
|
33
|
+
Tool.current_ledger = @ledger
|
|
34
|
+
Tool.current_tool_result_collector = tool_result_collector
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def teardown_step_context
|
|
38
|
+
Tool.current_guardrails = nil
|
|
39
|
+
Tool.current_deadline = nil
|
|
40
|
+
Tool.current_ledger = nil
|
|
41
|
+
Tool.current_tool_result_collector = nil
|
|
42
|
+
Smith.scoped_artifacts = nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smith
|
|
4
|
+
class Workflow
|
|
5
|
+
class StringSnapshot
|
|
6
|
+
BYTESIZE = String.instance_method(:bytesize)
|
|
7
|
+
FREEZE = String.instance_method(:freeze)
|
|
8
|
+
INITIALIZE_COPY = String.instance_method(:initialize_copy)
|
|
9
|
+
private_constant :BYTESIZE, :FREEZE, :INITIALIZE_COPY
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
def bytesize(value)
|
|
13
|
+
BYTESIZE.bind_call(value)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def copy(value, freeze: false)
|
|
17
|
+
String.allocate.tap do |copy|
|
|
18
|
+
INITIALIZE_COPY.bind_call(copy, value)
|
|
19
|
+
FREEZE.bind_call(copy) if freeze
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry-initializer"
|
|
4
|
+
|
|
5
|
+
require_relative "process_local"
|
|
6
|
+
|
|
7
|
+
module Smith
|
|
8
|
+
class Workflow
|
|
9
|
+
class ThreadContextSnapshot
|
|
10
|
+
extend Dry::Initializer
|
|
11
|
+
include ProcessLocal
|
|
12
|
+
|
|
13
|
+
TOOL_ATTRIBUTES = %i[
|
|
14
|
+
current_guardrails
|
|
15
|
+
current_deadline
|
|
16
|
+
current_ledger
|
|
17
|
+
current_tool_call_allowance
|
|
18
|
+
current_tool_result_collector
|
|
19
|
+
].freeze
|
|
20
|
+
THREAD_KEYS = %i[
|
|
21
|
+
smith_call_deadline
|
|
22
|
+
smith_call_ledger
|
|
23
|
+
smith_failed_agent_results
|
|
24
|
+
smith_last_agent_result
|
|
25
|
+
smith_parallel_agent_binding
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
option :tool_attributes, default: proc { TOOL_ATTRIBUTES }
|
|
29
|
+
option :thread_keys, default: proc { THREAD_KEYS }
|
|
30
|
+
option :scoped_artifacts, default: proc { true }
|
|
31
|
+
|
|
32
|
+
def initialize(...)
|
|
33
|
+
super
|
|
34
|
+
@tool_attributes = tool_attributes.dup.freeze
|
|
35
|
+
@thread_keys = thread_keys.dup.freeze
|
|
36
|
+
validate_selection!
|
|
37
|
+
@tool_values = capture_tool_values
|
|
38
|
+
@thread_values = capture_thread_values
|
|
39
|
+
@artifact_store = Smith.scoped_artifacts if scoped_artifacts
|
|
40
|
+
@process_id = Process.pid
|
|
41
|
+
@thread = Thread.current
|
|
42
|
+
@fiber = Fiber.current
|
|
43
|
+
@restored = false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def restore!
|
|
47
|
+
ensure_owner!
|
|
48
|
+
Thread.handle_interrupt(Object => :never) { restore_context! }
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def around
|
|
53
|
+
ensure_owner!
|
|
54
|
+
Thread.handle_interrupt(Object => :never) do
|
|
55
|
+
raise WorkflowError, "thread context snapshot has already been restored" if @restored
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
yield
|
|
59
|
+
ensure
|
|
60
|
+
restore_context!
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def restore_context!
|
|
68
|
+
raise WorkflowError, "thread context snapshot has already been restored" if @restored
|
|
69
|
+
|
|
70
|
+
@tool_values.each { |attribute, value| Tool.public_send("#{attribute}=", value) }
|
|
71
|
+
@thread_values.each { |key, value| Thread.current[key] = value }
|
|
72
|
+
Smith.scoped_artifacts = @artifact_store if scoped_artifacts
|
|
73
|
+
@restored = true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def capture_tool_values
|
|
77
|
+
tool_attributes.to_h { |attribute| [attribute, Tool.public_send(attribute)] }.freeze
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def capture_thread_values
|
|
81
|
+
thread_keys.to_h { |key| [key, Thread.current[key]] }.freeze
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ensure_owner!
|
|
85
|
+
owner = @process_id == Process.pid && @thread.equal?(Thread.current) && @fiber.equal?(Fiber.current)
|
|
86
|
+
return if owner
|
|
87
|
+
|
|
88
|
+
raise WorkflowError, "thread context snapshot belongs to another process, thread, or fiber"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def validate_selection!
|
|
92
|
+
unless (tool_attributes - TOOL_ATTRIBUTES).empty?
|
|
93
|
+
raise ArgumentError, "thread context snapshot contains unsupported tool attributes"
|
|
94
|
+
end
|
|
95
|
+
return if (thread_keys - THREAD_KEYS).empty?
|
|
96
|
+
|
|
97
|
+
raise ArgumentError, "thread context snapshot contains unsupported thread keys"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private_constant :ThreadContextSnapshot
|
|
102
|
+
end
|
|
103
|
+
end
|