bitfab 0.23.2 → 0.23.4
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/README.md +7 -6
- data/lib/bitfab/client.rb +5 -5
- data/lib/bitfab/replay.rb +36 -12
- data/lib/bitfab/traceable.rb +4 -4
- data/lib/bitfab/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c6103564370cdb20d6ed221a57c1cd29f8e410cd23ad3218b4eb0bda3ff3bd1
|
|
4
|
+
data.tar.gz: aded540c60d09f0838e529fc7616659fc6d64ad5dbcaf12baf396b164d741f7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ee3df19ee7101db92bea5305f61c67cc92d1bb5cdf4999cde05f31ee15b7e5090d5f474a35abb5814ca799a8849cea1cc3eda55064ec72bd2ac601c251622a0
|
|
7
|
+
data.tar.gz: 6729607659c50822d1799e86dfc3219cf7cfa5d47a8d9e82d5e8904918f3378a4d98b8f6a0bf9435ed8f34b147d96b061730424cbd2ce0a132d82e3a10c3f415
|
data/README.md
CHANGED
|
@@ -291,17 +291,18 @@ fn.wrap(OpenAI::Client, :embeddings, name: "Embed", type: "llm")
|
|
|
291
291
|
|
|
292
292
|
### Replay with Mock Strategies
|
|
293
293
|
|
|
294
|
-
Replay reruns historical traces through your code so you can compare outputs after an iteration. By default
|
|
294
|
+
Replay reruns historical traces through your code so you can compare outputs after an iteration. By default, spans tagged with `mock_on_replay: true` return their historical output and other child spans run real code. Three strategies control whether child spans return their historical output instead of executing:
|
|
295
295
|
|
|
296
296
|
```ruby
|
|
297
|
-
# "
|
|
297
|
+
# "marked" (default): only spans tagged with `mock_on_replay: true` return historical output
|
|
298
|
+
client.replay(pipeline, :process, trace_function_key: "my-fn")
|
|
299
|
+
client.replay(pipeline, :process, trace_function_key: "my-fn", mock: "marked")
|
|
300
|
+
|
|
301
|
+
# "none": everything runs real code
|
|
298
302
|
client.replay(pipeline, :process, trace_function_key: "my-fn", mock: "none")
|
|
299
303
|
|
|
300
304
|
# "all": every child span returns its historical output
|
|
301
305
|
client.replay(pipeline, :process, trace_function_key: "my-fn", mock: "all")
|
|
302
|
-
|
|
303
|
-
# "marked": only spans tagged with `mock_on_replay: true` return historical output
|
|
304
|
-
client.replay(pipeline, :process, trace_function_key: "my-fn", mock: "marked")
|
|
305
306
|
```
|
|
306
307
|
|
|
307
308
|
Tag the spans you want mocked at definition time:
|
|
@@ -330,7 +331,7 @@ class Pipeline
|
|
|
330
331
|
end
|
|
331
332
|
```
|
|
332
333
|
|
|
333
|
-
Use `mock: "marked"` when you want to iterate on `process`'s logic without paying for the LLM call each run. Use `mock: "all"` for the cheapest possible replay (every child span returns its recorded output).
|
|
334
|
+
Use the default `mock: "marked"` behavior when you want to iterate on `process`'s logic without paying for the LLM call each run. Use `mock: "all"` for the cheapest possible replay (every child span returns its recorded output).
|
|
334
335
|
|
|
335
336
|
### Error Handling
|
|
336
337
|
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -72,9 +72,9 @@ module Bitfab
|
|
|
72
72
|
# replay runs into a single experiment batch
|
|
73
73
|
# @param dataset_id [String, nil] optional UUID of the dataset this replay
|
|
74
74
|
# runs against, stored on the resulting experiment for durable attribution
|
|
75
|
-
# @param mock [String] mock strategy for child spans: "
|
|
76
|
-
# "
|
|
77
|
-
#
|
|
75
|
+
# @param mock [String] mock strategy for child spans: "marked" (default),
|
|
76
|
+
# "none", or "all". "marked" only mocks spans declared with
|
|
77
|
+
# mock_on_replay: true; "all" mocks every child span.
|
|
78
78
|
# @param adapt_inputs [#call, nil] optional hook to reshape recorded inputs
|
|
79
79
|
# onto the method's current signature when its shape changed after the
|
|
80
80
|
# traces were captured. Receives (args, kwargs, ctx) where ctx is
|
|
@@ -87,7 +87,7 @@ module Bitfab
|
|
|
87
87
|
# A raising callback never crashes the run.
|
|
88
88
|
# @return [Hash] with :items, :test_run_id, :test_run_url
|
|
89
89
|
def replay(receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, max_concurrency: 10,
|
|
90
|
-
name: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, dataset_id: nil, mock: "
|
|
90
|
+
name: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, dataset_id: nil, mock: "marked",
|
|
91
91
|
adapt_inputs: nil, environment: nil, on_progress: nil)
|
|
92
92
|
Replay.run(
|
|
93
93
|
self, receiver, method_name,
|
|
@@ -673,7 +673,7 @@ module Bitfab
|
|
|
673
673
|
# @param method_name [Symbol] the method to wrap
|
|
674
674
|
# @param name [String, nil] explicit span name (defaults to method name)
|
|
675
675
|
# @param type [String] span type
|
|
676
|
-
# @param mock_on_replay [Boolean] mark this span for the "marked" mock strategy
|
|
676
|
+
# @param mock_on_replay [Boolean] mark this span for the default "marked" mock strategy
|
|
677
677
|
def wrap(klass, method_name, name: nil, type: "custom", mock_on_replay: false)
|
|
678
678
|
Bitfab::Traceable.wrap(
|
|
679
679
|
klass, method_name,
|
data/lib/bitfab/replay.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
3
6
|
require_relative "constants"
|
|
4
7
|
require_relative "serialize"
|
|
5
8
|
require_relative "traceable"
|
|
@@ -7,10 +10,10 @@ require_relative "traceable"
|
|
|
7
10
|
module Bitfab
|
|
8
11
|
# Replay mock strategies. Mirrors the Python and TypeScript SDKs.
|
|
9
12
|
#
|
|
10
|
-
# - "none" : every child span runs real code (default)
|
|
11
|
-
# - "all" : every child span returns its historical output
|
|
12
13
|
# - "marked" : only spans declared with mock_on_replay: true return historical
|
|
13
|
-
# output; everything else runs real code
|
|
14
|
+
# output; everything else runs real code (default)
|
|
15
|
+
# - "none" : every child span runs real code
|
|
16
|
+
# - "all" : every child span returns its historical output
|
|
14
17
|
MOCK_STRATEGIES = %w[none all marked].freeze
|
|
15
18
|
|
|
16
19
|
# Thread-local replay context management.
|
|
@@ -40,7 +43,7 @@ module Bitfab
|
|
|
40
43
|
ctx[:pending_persistence] = pending_persistence if pending_persistence
|
|
41
44
|
if mock_tree
|
|
42
45
|
ctx[:mock_tree] = mock_tree
|
|
43
|
-
ctx[:mock_strategy] = mock_strategy || "
|
|
46
|
+
ctx[:mock_strategy] = mock_strategy || "marked"
|
|
44
47
|
ctx[:call_counters] = {}
|
|
45
48
|
end
|
|
46
49
|
# The per-trace DB branch (resolved server-side) and the Bitfab trace ID
|
|
@@ -92,9 +95,9 @@ module Bitfab
|
|
|
92
95
|
# replay runs into a single experiment batch
|
|
93
96
|
# @param dataset_id [String, nil] optional UUID of the dataset this replay
|
|
94
97
|
# runs against, stored on the resulting experiment for durable attribution
|
|
95
|
-
# @param mock [String] mock strategy for child spans: "
|
|
96
|
-
# "
|
|
97
|
-
#
|
|
98
|
+
# @param mock [String] mock strategy for child spans: "marked" (default),
|
|
99
|
+
# "none", or "all". "marked" only mocks spans declared with
|
|
100
|
+
# mock_on_replay: true; "all" mocks every child span.
|
|
98
101
|
# @param adapt_inputs [#call, nil] optional hook to reshape recorded inputs
|
|
99
102
|
# onto the method's current signature when its shape changed after the
|
|
100
103
|
# traces were captured. Receives (args, kwargs, ctx) where ctx is
|
|
@@ -112,7 +115,7 @@ module Bitfab
|
|
|
112
115
|
# @return [Hash] with :items, :test_run_id, :test_run_url
|
|
113
116
|
def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil,
|
|
114
117
|
max_concurrency: 10, code_change_description: nil, code_change_files: nil, experiment_group_id: nil,
|
|
115
|
-
dataset_id: nil, mock: "
|
|
118
|
+
dataset_id: nil, mock: "marked",
|
|
116
119
|
adapt_inputs: nil, environment: nil, on_progress: nil)
|
|
117
120
|
unless MOCK_STRATEGIES.include?(mock.to_s)
|
|
118
121
|
raise ArgumentError, "Invalid mock strategy '#{mock}'. Must be one of: #{MOCK_STRATEGIES.join(", ")}"
|
|
@@ -239,11 +242,26 @@ module Bitfab
|
|
|
239
242
|
end
|
|
240
243
|
end
|
|
241
244
|
|
|
242
|
-
{
|
|
245
|
+
replay_result = {
|
|
243
246
|
items: result_items,
|
|
244
247
|
test_run_id:,
|
|
245
248
|
test_run_url: "#{client.service_url}#{test_run_url}"
|
|
246
249
|
}
|
|
250
|
+
write_replay_result_file(replay_result)
|
|
251
|
+
replay_result
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def write_replay_result_file(result)
|
|
255
|
+
result_path = ENV["BITFAB_REPLAY_RESULT_PATH"]
|
|
256
|
+
return if result_path.nil? || result_path.empty?
|
|
257
|
+
|
|
258
|
+
begin
|
|
259
|
+
dir = File.dirname(result_path)
|
|
260
|
+
FileUtils.mkdir_p(dir) unless dir.nil? || dir.empty? || dir == "."
|
|
261
|
+
File.write(result_path, "#{JSON.pretty_generate(result)}\n")
|
|
262
|
+
rescue => e
|
|
263
|
+
warn "Bitfab: failed to write replay result to BITFAB_REPLAY_RESULT_PATH (#{result_path}): #{e.message}"
|
|
264
|
+
end
|
|
247
265
|
end
|
|
248
266
|
|
|
249
267
|
# Process all replay items, optionally in parallel using threads.
|
|
@@ -349,8 +367,14 @@ module Bitfab
|
|
|
349
367
|
|
|
350
368
|
mock_tree = nil
|
|
351
369
|
if mock_strategy == "all" || mock_strategy == "marked"
|
|
352
|
-
|
|
353
|
-
|
|
370
|
+
begin
|
|
371
|
+
tree = http_client.get_span_tree(server_item["externalSpanId"])
|
|
372
|
+
mock_tree = build_mock_tree(tree["root"] || {})
|
|
373
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
374
|
+
raise if e.is_a?(SystemExit) || e.is_a?(SignalException)
|
|
375
|
+
raise if mock_strategy == "all"
|
|
376
|
+
mock_tree = nil
|
|
377
|
+
end
|
|
354
378
|
end
|
|
355
379
|
|
|
356
380
|
adapt_ctx = {trace_id: server_item["traceId"], source_span_id: server_item["externalSpanId"]}
|
|
@@ -481,7 +505,7 @@ module Bitfab
|
|
|
481
505
|
|
|
482
506
|
# Execute a single replay item: deserialize inputs, call method with replay context.
|
|
483
507
|
def execute_item(item, receiver, method_name, test_run_id, input_source_span_id = nil, metrics = {},
|
|
484
|
-
input_source_trace_id: nil, mock_strategy: "
|
|
508
|
+
input_source_trace_id: nil, mock_strategy: "marked", mock_tree: nil, adapt_inputs: nil, adapt_ctx: nil,
|
|
485
509
|
db_branch_lease: nil, source_bitfab_trace_id: nil, db_snapshot_ref: nil)
|
|
486
510
|
args, kwargs = Serialize.deserialize_inputs(item)
|
|
487
511
|
|
data/lib/bitfab/traceable.rb
CHANGED
|
@@ -38,8 +38,8 @@ module Bitfab
|
|
|
38
38
|
# @param trace_function_key [String] the trace function key
|
|
39
39
|
# @param name [String, nil] explicit span name (defaults to method name)
|
|
40
40
|
# @param type [String] span type: llm, agent, function, guardrail, handoff, custom
|
|
41
|
-
# @param mock_on_replay [Boolean] mark this span for the "marked" mock strategy.
|
|
42
|
-
# When true, `client.replay(...
|
|
41
|
+
# @param mock_on_replay [Boolean] mark this span for the default "marked" mock strategy.
|
|
42
|
+
# When true, `client.replay(...)` returns this span's
|
|
43
43
|
# historical output instead of executing the wrapped method.
|
|
44
44
|
# @param client [Bitfab::Client, nil] route spans through this specific client
|
|
45
45
|
# instead of the global `Bitfab.client`. When nil (default), the wrapper
|
|
@@ -132,8 +132,8 @@ module Bitfab
|
|
|
132
132
|
# @param trace_function_key [String, nil] trace function key (overrides class-level bitfab_function)
|
|
133
133
|
# @param name [String, nil] explicit span name (defaults to method name)
|
|
134
134
|
# @param type [String] span type: llm, agent, function, guardrail, handoff, custom
|
|
135
|
-
# @param mock_on_replay [Boolean] mark this span for the "marked" mock strategy.
|
|
136
|
-
# When true, `client.replay(...
|
|
135
|
+
# @param mock_on_replay [Boolean] mark this span for the default "marked" mock strategy.
|
|
136
|
+
# When true, `client.replay(...)` returns this span's
|
|
137
137
|
# historical output instead of executing the wrapped method.
|
|
138
138
|
def bitfab_span(method_name, trace_function_key: nil, name: nil, type: "custom", mock_on_replay: false)
|
|
139
139
|
trace_function_key ||= @bitfab_function_key
|
data/lib/bitfab/version.rb
CHANGED