smith-agents 0.8.0 → 0.11.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 +433 -0
- data/README.md +16 -6
- data/docs/CONFIGURATION.md +26 -6
- data/docs/PATTERNS.md +59 -0
- data/docs/PERSISTENCE.md +5 -1
- data/lib/smith/agent/completion_usage_recording.rb +21 -3
- data/lib/smith/agent/fallback_configuration.rb +26 -3
- data/lib/smith/agent/invocation_preparation.rb +24 -0
- data/lib/smith/agent/lifecycle.rb +4 -2
- data/lib/smith/agent/provider_attempt.rb +17 -4
- data/lib/smith/agent/provider_call_timing.rb +129 -0
- data/lib/smith/agent/provider_completion.rb +26 -8
- data/lib/smith/agent/provider_failure_handling.rb +2 -2
- data/lib/smith/agent/provider_usage.rb +6 -0
- data/lib/smith/agent/usage_entry_recording.rb +27 -4
- data/lib/smith/agent/usage_traces.rb +49 -0
- data/lib/smith/agent/usage_tracking.rb +26 -20
- data/lib/smith/agent.rb +9 -1
- data/lib/smith/attribution.rb +115 -0
- data/lib/smith/budget/amount_representation.rb +20 -0
- data/lib/smith/budget/ledger.rb +6 -2
- data/lib/smith/context/state_injection.rb +12 -2
- data/lib/smith/diagnostic_text.rb +10 -1
- data/lib/smith/doctor/checks/durability.rb +16 -0
- data/lib/smith/doctor/checks/persistence_capabilities.rb +13 -7
- data/lib/smith/errors.rb +55 -4
- data/lib/smith/event.rb +10 -2
- data/lib/smith/events/bus.rb +63 -5
- data/lib/smith/events/step_completed.rb +3 -0
- data/lib/smith/events/step_failed.rb +25 -0
- data/lib/smith/events/subscription.rb +8 -0
- data/lib/smith/persistence_adapters/active_record_exact_store.rb +8 -3
- data/lib/smith/persistence_adapters/active_record_store.rb +4 -7
- data/lib/smith/persistence_adapters.rb +10 -0
- data/lib/smith/provider_permanent_failure.rb +44 -0
- data/lib/smith/tool/capture.rb +9 -1
- data/lib/smith/tool.rb +10 -1
- data/lib/smith/trace/logger.rb +1 -0
- data/lib/smith/trace/memory.rb +40 -4
- data/lib/smith/trace/open_telemetry.rb +47 -3
- data/lib/smith/trace.rb +24 -5
- data/lib/smith/version.rb +1 -1
- data/lib/smith/workflow/budget_integration.rb +3 -3
- data/lib/smith/workflow/composite/effects.rb +64 -33
- data/lib/smith/workflow/deterministic_execution.rb +3 -2
- data/lib/smith/workflow/deterministic_step.rb +15 -2
- data/lib/smith/workflow/dsl.rb +40 -6
- data/lib/smith/workflow/durability.rb +1 -1
- data/lib/smith/workflow/evaluator_optimizer.rb +111 -11
- data/lib/smith/workflow/event_integration.rb +48 -1
- data/lib/smith/workflow/execution.rb +10 -0
- data/lib/smith/workflow/failure_reconstructor.rb +18 -2
- data/lib/smith/workflow/failure_record.rb +6 -11
- data/lib/smith/workflow/failure_record_validator.rb +23 -3
- data/lib/smith/workflow/fanout_execution.rb +1 -1
- data/lib/smith/workflow/guardrail_integration.rb +27 -0
- data/lib/smith/workflow/optimization_state.rb +2 -2
- data/lib/smith/workflow/parallel_execution.rb +6 -0
- data/lib/smith/workflow/persistence.rb +55 -6
- data/lib/smith/workflow/prepared_branch_execution.rb +13 -4
- data/lib/smith/workflow/retry_execution.rb +4 -0
- data/lib/smith/workflow/run_result.rb +10 -0
- data/lib/smith/workflow/split_step_persistence/composite_branch_execution.rb +9 -1
- data/lib/smith/workflow/split_step_persistence/state_snapshot.rb +1 -0
- data/lib/smith/workflow/step_completion.rb +13 -0
- data/lib/smith/workflow/step_context.rb +46 -0
- data/lib/smith/workflow/thread_context_snapshot.rb +1 -0
- data/lib/smith/workflow/usage_entry.rb +32 -4
- data/lib/smith/workflow.rb +30 -3
- data/lib/smith.rb +9 -4
- metadata +5 -1
|
@@ -33,6 +33,16 @@ module Smith
|
|
|
33
33
|
steps.reverse.map { |step| step[:error] }.compact.first
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Every verdict an optimize step's loops recorded, in step, attempt and
|
|
37
|
+
# round order, each a frozen record naming its step's transition. Like
|
|
38
|
+
# `steps`, they belong to the run that executed the step: a terminal
|
|
39
|
+
# restore has none.
|
|
40
|
+
def evaluations
|
|
41
|
+
steps.flat_map do |step|
|
|
42
|
+
(step[:evaluations] || []).map { |evaluation| { transition: step[:transition], **evaluation }.freeze }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
36
46
|
def failed_transition
|
|
37
47
|
failure_detail&.fetch(:transition)
|
|
38
48
|
end
|
|
@@ -40,7 +40,15 @@ module Smith
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def capture_composite_branch(&block)
|
|
43
|
-
output = within_raw_step_context
|
|
43
|
+
output = within_raw_step_context do
|
|
44
|
+
# Same ambient attribution the in-process step path installs, so
|
|
45
|
+
# durably executed branches tag usage and traces identically
|
|
46
|
+
# (execution key from the restored persistence key, the split
|
|
47
|
+
# step's transition, then the branch overlay downstream).
|
|
48
|
+
# Restoration is owned by within_raw_step_context's snapshot.
|
|
49
|
+
install_step_attribution(@split_step_transition) if @split_step_transition
|
|
50
|
+
with_scoped_artifacts(&block)
|
|
51
|
+
end
|
|
44
52
|
[output, nil]
|
|
45
53
|
rescue StandardError => e
|
|
46
54
|
[nil, e]
|
|
@@ -58,6 +58,7 @@ module Smith
|
|
|
58
58
|
|
|
59
59
|
def detach_split_step_results!
|
|
60
60
|
@last_output = snapshot_value(@last_output)
|
|
61
|
+
@last_agent_execution = snapshot_value(@last_agent_execution)
|
|
61
62
|
@last_failed_step = snapshot_value(@last_failed_step)
|
|
62
63
|
@last_prepared_input = snapshot_value(@last_prepared_input)
|
|
63
64
|
end
|
|
@@ -7,6 +7,16 @@ module Smith
|
|
|
7
7
|
|
|
8
8
|
def complete_step(transition, output)
|
|
9
9
|
step = { transition: transition.name, from: transition.from, to: transition.to, output: output }
|
|
10
|
+
# Fold in the serial agent attribution captured for this step (if any),
|
|
11
|
+
# then clear the transient carrier. record_step_snapshot reads these off
|
|
12
|
+
# the returned step to update the durable @last_agent_execution.
|
|
13
|
+
if @pending_agent_execution
|
|
14
|
+
step[:model] = @pending_agent_execution[:model]
|
|
15
|
+
step[:provider] = @pending_agent_execution[:provider]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@pending_agent_execution = nil
|
|
19
|
+
fold_pending_evaluations(step)
|
|
10
20
|
result = SplitStepPersistence
|
|
11
21
|
.instance_method(:prepare_split_step_execution_result)
|
|
12
22
|
.bind_call(self, step)
|
|
@@ -14,6 +24,9 @@ module Smith
|
|
|
14
24
|
SplitStepPersistence
|
|
15
25
|
.instance_method(:commit_split_step_execution_result!)
|
|
16
26
|
.bind_call(self, result)
|
|
27
|
+
# Cleared only once the record is committed: a completion that fails
|
|
28
|
+
# before this folds the same verdicts into its failure record.
|
|
29
|
+
@pending_evaluations = nil
|
|
17
30
|
@state = transition.to
|
|
18
31
|
@next_transition_name = @router_next_transition || transition.success_transition
|
|
19
32
|
@router_next_transition = nil
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../attribution"
|
|
3
4
|
require_relative "thread_context_snapshot"
|
|
4
5
|
|
|
5
6
|
module Smith
|
|
@@ -10,6 +11,7 @@ module Smith
|
|
|
10
11
|
def with_step_context(transition, &block)
|
|
11
12
|
ThreadContextSnapshot.new.around do
|
|
12
13
|
setup_step_context
|
|
14
|
+
install_step_attribution(transition)
|
|
13
15
|
Thread.handle_interrupt(Object => :immediate, &block)
|
|
14
16
|
rescue StandardError => e
|
|
15
17
|
@outcome = nil
|
|
@@ -17,6 +19,32 @@ module Smith
|
|
|
17
19
|
ensure
|
|
18
20
|
teardown_step_context
|
|
19
21
|
end
|
|
22
|
+
ensure
|
|
23
|
+
flush_step_failure_emission
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Runs after the snapshot's interrupt mask has closed, so host
|
|
27
|
+
# StepFailed handlers execute interruptible, exactly as StepCompleted
|
|
28
|
+
# handlers do inside the step. The step context is gone by now, so the
|
|
29
|
+
# run identity and workflow label are seeded explicitly; the failed
|
|
30
|
+
# step's own transition facts travel in the staged step hash. Flushes
|
|
31
|
+
# on every exit of with_step_context, including the re-raise paths.
|
|
32
|
+
# The read-clear-mark triple is masked so an async interrupt cannot
|
|
33
|
+
# strand a staged failure between read and clear; the marker lets the
|
|
34
|
+
# unresolved-transition handler recognize an error this path already
|
|
35
|
+
# emitted. Only the emission itself stays interruptible.
|
|
36
|
+
def flush_step_failure_emission
|
|
37
|
+
step = nil
|
|
38
|
+
Thread.handle_interrupt(Object => :never) do
|
|
39
|
+
step = @pending_step_failure
|
|
40
|
+
@pending_step_failure = nil
|
|
41
|
+
@emitted_step_failure_error = step[:error] if step
|
|
42
|
+
end
|
|
43
|
+
return unless step
|
|
44
|
+
|
|
45
|
+
Attribution.with(execution_key: @persistence_key, workflow: self.class.name || "anonymous") do
|
|
46
|
+
emit_step_failed(step)
|
|
47
|
+
end
|
|
20
48
|
end
|
|
21
49
|
|
|
22
50
|
def within_raw_step_context(&block)
|
|
@@ -34,6 +62,24 @@ module Smith
|
|
|
34
62
|
Tool.current_tool_result_collector = tool_result_collector
|
|
35
63
|
end
|
|
36
64
|
|
|
65
|
+
# The ambient attribution for this step. Restoration is owned by the
|
|
66
|
+
# surrounding ThreadContextSnapshot (the attribution thread key is one
|
|
67
|
+
# of its THREAD_KEYS), so installation is a plain assignment. A nil
|
|
68
|
+
# persistence key preserves any host-seeded outer execution_key, and
|
|
69
|
+
# `workflow` is always a string ("anonymous" when the class has no
|
|
70
|
+
# name) so a nested child always overrides the parent's label. The
|
|
71
|
+
# per-step facts (transition, from, to) are replaced verbatim, nil
|
|
72
|
+
# included: a nested child's `from: nil` transition must not inherit
|
|
73
|
+
# the parent step's `from` through the nil-ignoring merge. branch_key
|
|
74
|
+
# and round inherit deliberately (a child genuinely runs within them).
|
|
75
|
+
def install_step_attribution(transition)
|
|
76
|
+
Attribution.install(
|
|
77
|
+
Attribution.ambient
|
|
78
|
+
.merge(execution_key: @persistence_key, workflow: self.class.name || "anonymous")
|
|
79
|
+
.override(transition: transition.name, from: transition.from, to: transition.to)
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
37
83
|
def teardown_step_context
|
|
38
84
|
Tool.current_guardrails = nil
|
|
39
85
|
Tool.current_deadline = nil
|
|
@@ -2,9 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Smith
|
|
4
4
|
class Workflow
|
|
5
|
-
# One row per
|
|
6
|
-
#
|
|
7
|
-
# idempotency anchor.
|
|
5
|
+
# One row per provider RESPONSE within an agent provider attempt.
|
|
6
|
+
# `usage_id` is a UUID generated at recording time and stable across
|
|
7
|
+
# persist/restore so hosts can use it as an idempotency anchor.
|
|
8
|
+
#
|
|
9
|
+
# `transition`, `branch_key`, `round`, and `workflow` come from the
|
|
10
|
+
# ambient Smith::Attribution at recording time, so hosts can attribute
|
|
11
|
+
# usage to the exact step, fan-out branch, optimizer round, and (for
|
|
12
|
+
# nested workflows) the exact graph that spent it.
|
|
13
|
+
# `attempt_id` is shared by every entry the same provider attempt
|
|
14
|
+
# produced (an attempt with an N-round tool loop records N entries):
|
|
15
|
+
# join on it against the `:provider_call` trace event for the attempt's
|
|
16
|
+
# single measured duration; never sum a duration across entries. Every
|
|
17
|
+
# attempt emits its `:provider_call` (an attempt aborted by a
|
|
18
|
+
# non-provider error emits with `outcome: :aborted` before re-raising),
|
|
19
|
+
# so prefix-accounted entries always have their join target.
|
|
20
|
+
# All optional members are nil on entries restored from checkpoints written by
|
|
21
|
+
# earlier Smith versions, and nil attribution members are omitted from
|
|
22
|
+
# serialization so those documents re-serialize byte-identically.
|
|
8
23
|
# rubocop:disable Style/RedundantStructKeywordInit
|
|
9
24
|
UsageEntry = Struct.new(
|
|
10
25
|
:usage_id,
|
|
@@ -16,6 +31,11 @@ module Smith
|
|
|
16
31
|
:cost,
|
|
17
32
|
:attempt_kind,
|
|
18
33
|
:recorded_at,
|
|
34
|
+
:transition,
|
|
35
|
+
:branch_key,
|
|
36
|
+
:round,
|
|
37
|
+
:attempt_id,
|
|
38
|
+
:workflow,
|
|
19
39
|
keyword_init: true
|
|
20
40
|
) do
|
|
21
41
|
def initialize(**attributes)
|
|
@@ -26,10 +46,18 @@ module Smith
|
|
|
26
46
|
freeze
|
|
27
47
|
end
|
|
28
48
|
|
|
49
|
+
# Serialization is additive only when present: nil attribution members
|
|
50
|
+
# are omitted so an entry restored from a pre-attribution checkpoint
|
|
51
|
+
# re-serializes byte-identically. Hosts that digest whole persisted
|
|
52
|
+
# documents (exact-mutation proofs) depend on this stability.
|
|
53
|
+
def to_h
|
|
54
|
+
super.reject { |key, value| value.nil? && %i[transition branch_key round attempt_id workflow].include?(key) }
|
|
55
|
+
end
|
|
56
|
+
|
|
29
57
|
def self.from_h(hash)
|
|
30
58
|
sym = hash.transform_keys(&:to_sym)
|
|
31
59
|
filtered = sym.slice(*members)
|
|
32
|
-
%i[agent_name provider attempt_kind].each do |attribute|
|
|
60
|
+
%i[agent_name provider attempt_kind transition branch_key].each do |attribute|
|
|
33
61
|
filtered[attribute] = filtered[attribute].to_sym if filtered[attribute].is_a?(String)
|
|
34
62
|
end
|
|
35
63
|
new(**filtered)
|
data/lib/smith/workflow.rb
CHANGED
|
@@ -44,7 +44,7 @@ module Smith
|
|
|
44
44
|
@step_count = 0
|
|
45
45
|
@next_transition_name = nil
|
|
46
46
|
@ledger = ledger || build_ledger
|
|
47
|
-
@created_at = created_at || Time.now.utc.iso8601
|
|
47
|
+
@created_at = created_at || Time.now.utc.iso8601(6)
|
|
48
48
|
@updated_at = @created_at
|
|
49
49
|
@total_cost = 0.0
|
|
50
50
|
@total_tokens = 0
|
|
@@ -58,6 +58,16 @@ module Smith
|
|
|
58
58
|
@usage_entries = []
|
|
59
59
|
@usage_mutex = Mutex.new
|
|
60
60
|
@last_output = nil
|
|
61
|
+
# Durable attribution of the most recent serial `execute :agent` step:
|
|
62
|
+
# { model:, provider: } of the model that actually served it (post
|
|
63
|
+
# fallback resolution), exposed to the following deterministic step as
|
|
64
|
+
# `last_agent_model` / `last_agent_provider`. `@pending_agent_execution`
|
|
65
|
+
# is the transient per-step carrier from `execute_serial_step` to
|
|
66
|
+
# `complete_step`; it is never persisted. `@pending_evaluations` is the
|
|
67
|
+
# optimizer's, carrying a loop's verdicts into its step's record.
|
|
68
|
+
@last_agent_execution = nil
|
|
69
|
+
@pending_agent_execution = nil
|
|
70
|
+
@pending_evaluations = nil
|
|
61
71
|
@last_failed_step = nil
|
|
62
72
|
# Optimistic-locking version. Incremented on each persist!; restored
|
|
63
73
|
# from the persisted payload. Adapters that support store_versioned
|
|
@@ -112,7 +122,7 @@ module Smith
|
|
|
112
122
|
execute_step(transition)
|
|
113
123
|
end
|
|
114
124
|
@step_count += 1
|
|
115
|
-
@updated_at = Time.now.utc.iso8601
|
|
125
|
+
@updated_at = Time.now.utc.iso8601(6)
|
|
116
126
|
record_step_snapshot(step_result)
|
|
117
127
|
step_result
|
|
118
128
|
rescue UnresolvedTransitionError => e
|
|
@@ -157,6 +167,18 @@ module Smith
|
|
|
157
167
|
end
|
|
158
168
|
end
|
|
159
169
|
|
|
170
|
+
# Public, read-only view of the per-provider-call usage ledger, so hosts
|
|
171
|
+
# can diff usage across a step boundary without paying a full to_state
|
|
172
|
+
# serialization. The entries themselves are frozen; the returned array is
|
|
173
|
+
# a frozen copy taken under the recording mutex. Tolerates allocated but
|
|
174
|
+
# unrestored instances (no mutex yet), which have no entries.
|
|
175
|
+
def usage_entries
|
|
176
|
+
mutex = @usage_mutex
|
|
177
|
+
return [].freeze unless mutex
|
|
178
|
+
|
|
179
|
+
mutex.synchronize { @usage_entries.dup.freeze }
|
|
180
|
+
end
|
|
181
|
+
|
|
160
182
|
private
|
|
161
183
|
|
|
162
184
|
def initial_persist_auto_seed
|
|
@@ -189,6 +211,10 @@ module Smith
|
|
|
189
211
|
# matches `RunResult#output`'s `.compact.first` semantics).
|
|
190
212
|
@last_failed_step = nil
|
|
191
213
|
@last_output = step_result[:output] if step_result.key?(:output) && !step_result[:output].nil?
|
|
214
|
+
# Capture serial agent attribution only on steps that carried it (an
|
|
215
|
+
# `execute :agent` step); deterministic steps have no :model key, so
|
|
216
|
+
# the last agent execution persists across intervening compute steps.
|
|
217
|
+
@last_agent_execution = { model: step_result[:model], provider: step_result[:provider] } if step_result.key?(:model)
|
|
192
218
|
end
|
|
193
219
|
end
|
|
194
220
|
|
|
@@ -340,7 +366,8 @@ module Smith
|
|
|
340
366
|
# Same rule applies to nested-workflow rollup (see
|
|
341
367
|
# `nested_execution.rb`).
|
|
342
368
|
def snapshot_usage_entries
|
|
343
|
-
@
|
|
369
|
+
entries = @usage_mutex.synchronize { @usage_entries.dup }
|
|
370
|
+
entries.map { |entry| Workflow::UsageEntry.from_h(snapshot_value(entry.to_h)) }
|
|
344
371
|
end
|
|
345
372
|
|
|
346
373
|
def tool_result_collector
|
data/lib/smith.rb
CHANGED
|
@@ -40,11 +40,15 @@ module Smith
|
|
|
40
40
|
setting :trace_transitions, default: true
|
|
41
41
|
setting :trace_tool_calls, default: true
|
|
42
42
|
setting :trace_token_usage, default: true
|
|
43
|
+
setting :trace_provider_calls, default: true
|
|
43
44
|
setting :trace_cost, default: true
|
|
44
45
|
setting :trace_fields
|
|
45
46
|
setting :trace_content, default: false
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
# Merge the ambient Smith::Attribution fields (execution_key, transition,
|
|
48
|
+
# branch_key, round, ...) into every trace payload. Attribution keys are
|
|
49
|
+
# identifiers, not content; they still pass through any configured
|
|
50
|
+
# trace_fields allowlist, and caller-supplied keys win on conflict.
|
|
51
|
+
setting :trace_attribution, default: true
|
|
48
52
|
|
|
49
53
|
# Pricing (§4.5 — model-call cost computation)
|
|
50
54
|
setting :pricing, default: nil
|
|
@@ -55,8 +59,8 @@ module Smith
|
|
|
55
59
|
|
|
56
60
|
# Persistence TTL in Integer seconds. nil (default) means workflows
|
|
57
61
|
# persist indefinitely. Adapters that natively support TTL (Redis,
|
|
58
|
-
# CacheStore, Memory) pass this through; ActiveRecordStore
|
|
59
|
-
#
|
|
62
|
+
# CacheStore, Memory) pass this through; ActiveRecordStore has no expiry
|
|
63
|
+
# column and refuses a non-nil TTL.
|
|
60
64
|
# Per-workflow `Workflow.persistence_ttl 1.day.to_i` DSL overrides this.
|
|
61
65
|
setting :persistence_ttl, default: nil
|
|
62
66
|
|
|
@@ -187,6 +191,7 @@ require_relative "smith/events"
|
|
|
187
191
|
require_relative "smith/events/subscription"
|
|
188
192
|
require_relative "smith/events/bus"
|
|
189
193
|
require_relative "smith/events/step_completed"
|
|
194
|
+
require_relative "smith/events/step_failed"
|
|
190
195
|
|
|
191
196
|
# Budget (depends on Errors)
|
|
192
197
|
require_relative "smith/budget"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smith-agents
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Ralak
|
|
@@ -162,6 +162,7 @@ files:
|
|
|
162
162
|
- lib/smith/agent/lifecycle.rb
|
|
163
163
|
- lib/smith/agent/model_reference.rb
|
|
164
164
|
- lib/smith/agent/provider_attempt.rb
|
|
165
|
+
- lib/smith/agent/provider_call_timing.rb
|
|
165
166
|
- lib/smith/agent/provider_candidate_sequence.rb
|
|
166
167
|
- lib/smith/agent/provider_completion.rb
|
|
167
168
|
- lib/smith/agent/provider_failure_handling.rb
|
|
@@ -173,11 +174,13 @@ files:
|
|
|
173
174
|
- lib/smith/agent/registry_binding.rb
|
|
174
175
|
- lib/smith/agent/reserved_input_bridge.rb
|
|
175
176
|
- lib/smith/agent/usage_entry_recording.rb
|
|
177
|
+
- lib/smith/agent/usage_traces.rb
|
|
176
178
|
- lib/smith/agent/usage_tracking.rb
|
|
177
179
|
- lib/smith/artifacts.rb
|
|
178
180
|
- lib/smith/artifacts/file.rb
|
|
179
181
|
- lib/smith/artifacts/memory.rb
|
|
180
182
|
- lib/smith/artifacts/scoped_store.rb
|
|
183
|
+
- lib/smith/attribution.rb
|
|
181
184
|
- lib/smith/budget.rb
|
|
182
185
|
- lib/smith/budget/amount_contract.rb
|
|
183
186
|
- lib/smith/budget/amount_representation.rb
|
|
@@ -218,6 +221,7 @@ files:
|
|
|
218
221
|
- lib/smith/events/.keep
|
|
219
222
|
- lib/smith/events/bus.rb
|
|
220
223
|
- lib/smith/events/step_completed.rb
|
|
224
|
+
- lib/smith/events/step_failed.rb
|
|
221
225
|
- lib/smith/events/subscription.rb
|
|
222
226
|
- lib/smith/exponential_backoff.rb
|
|
223
227
|
- lib/smith/guardrails.rb
|