smith-agents 0.8.0 → 0.10.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 +230 -0
- data/docs/CONFIGURATION.md +5 -5
- data/lib/smith/agent/completion_usage_recording.rb +21 -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 +10 -4
- data/lib/smith/agent/provider_call_timing.rb +74 -0
- data/lib/smith/agent/provider_completion.rb +27 -9
- data/lib/smith/agent/provider_failure_handling.rb +2 -2
- 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 +23 -20
- data/lib/smith/attribution.rb +115 -0
- 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/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/composite/effects.rb +64 -33
- data/lib/smith/workflow/deterministic_execution.rb +2 -1
- data/lib/smith/workflow/deterministic_step.rb +14 -1
- data/lib/smith/workflow/dsl.rb +25 -1
- data/lib/smith/workflow/evaluator_optimizer.rb +3 -1
- data/lib/smith/workflow/event_integration.rb +48 -1
- data/lib/smith/workflow/execution.rb +8 -0
- data/lib/smith/workflow/fanout_execution.rb +1 -1
- data/lib/smith/workflow/guardrail_integration.rb +25 -0
- data/lib/smith/workflow/parallel_execution.rb +6 -0
- data/lib/smith/workflow/persistence.rb +33 -1
- data/lib/smith/workflow/prepared_branch_execution.rb +13 -4
- 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 +9 -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 +26 -1
- data/lib/smith.rb +7 -2
- metadata +5 -1
|
@@ -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
|
@@ -58,6 +58,14 @@ 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.
|
|
67
|
+
@last_agent_execution = nil
|
|
68
|
+
@pending_agent_execution = nil
|
|
61
69
|
@last_failed_step = nil
|
|
62
70
|
# Optimistic-locking version. Incremented on each persist!; restored
|
|
63
71
|
# from the persisted payload. Adapters that support store_versioned
|
|
@@ -157,6 +165,18 @@ module Smith
|
|
|
157
165
|
end
|
|
158
166
|
end
|
|
159
167
|
|
|
168
|
+
# Public, read-only view of the per-provider-call usage ledger, so hosts
|
|
169
|
+
# can diff usage across a step boundary without paying a full to_state
|
|
170
|
+
# serialization. The entries themselves are frozen; the returned array is
|
|
171
|
+
# a frozen copy taken under the recording mutex. Tolerates allocated but
|
|
172
|
+
# unrestored instances (no mutex yet), which have no entries.
|
|
173
|
+
def usage_entries
|
|
174
|
+
mutex = @usage_mutex
|
|
175
|
+
return [].freeze unless mutex
|
|
176
|
+
|
|
177
|
+
mutex.synchronize { @usage_entries.dup.freeze }
|
|
178
|
+
end
|
|
179
|
+
|
|
160
180
|
private
|
|
161
181
|
|
|
162
182
|
def initial_persist_auto_seed
|
|
@@ -189,6 +209,10 @@ module Smith
|
|
|
189
209
|
# matches `RunResult#output`'s `.compact.first` semantics).
|
|
190
210
|
@last_failed_step = nil
|
|
191
211
|
@last_output = step_result[:output] if step_result.key?(:output) && !step_result[:output].nil?
|
|
212
|
+
# Capture serial agent attribution only on steps that carried it (an
|
|
213
|
+
# `execute :agent` step); deterministic steps have no :model key, so
|
|
214
|
+
# the last agent execution persists across intervening compute steps.
|
|
215
|
+
@last_agent_execution = { model: step_result[:model], provider: step_result[:provider] } if step_result.key?(:model)
|
|
192
216
|
end
|
|
193
217
|
end
|
|
194
218
|
|
|
@@ -340,7 +364,8 @@ module Smith
|
|
|
340
364
|
# Same rule applies to nested-workflow rollup (see
|
|
341
365
|
# `nested_execution.rb`).
|
|
342
366
|
def snapshot_usage_entries
|
|
343
|
-
@
|
|
367
|
+
entries = @usage_mutex.synchronize { @usage_entries.dup }
|
|
368
|
+
entries.map { |entry| Workflow::UsageEntry.from_h(snapshot_value(entry.to_h)) }
|
|
344
369
|
end
|
|
345
370
|
|
|
346
371
|
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
|
|
@@ -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.10.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
|