bitfab 0.23.6 → 0.23.8
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/lib/bitfab/client.rb +39 -2
- data/lib/bitfab/http_client.rb +14 -1
- data/lib/bitfab/span_context.rb +5 -0
- data/lib/bitfab/version.rb +1 -1
- data/lib/bitfab.rb +4 -0
- 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: 342b5de3b40edd60f060465123f21d1c5338063340b34ac7bb7067c7baedfe55
|
|
4
|
+
data.tar.gz: 2f73bec442f3570efe78253d28733942e00b46c03a26ce2731a72e778cd6d79f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c76023257bcdd959cb49d6881faf05e85013b2d30c02826fd57a2a2aa8a72d72d7f8f10716f9f4b2d850a84dfb4a6ef7151077b88f43e2e1e7bd5b4c81ed23ff
|
|
7
|
+
data.tar.gz: 37fb2e1215527c780253dd35e10e4ff01d735336d068d5d8ac16a75d4fcc17e1749f7718cf8ffc550e965a27a9f0ee8fb49b2b847724c10a1ae031f0f1470574
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative "warn_once"
|
|
|
13
13
|
module Bitfab
|
|
14
14
|
class Client
|
|
15
15
|
SPAN_TYPES = %w[llm agent function guardrail handoff custom].freeze
|
|
16
|
+
UUID_PATTERN = /\A[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i
|
|
16
17
|
|
|
17
18
|
# Sentinel returned by check_mock_replay when this span should run real
|
|
18
19
|
# code (no mock active, wrong strategy, or no matching historical entry).
|
|
@@ -115,6 +116,26 @@ module Bitfab
|
|
|
115
116
|
BitfabFunction.new(self, trace_function_key)
|
|
116
117
|
end
|
|
117
118
|
|
|
119
|
+
# Fetch one persisted span without loading the full trace.
|
|
120
|
+
# Exactly one of id or name is required. Name lookups return the last
|
|
121
|
+
# matching span by default; occurrence also accepts "first" or a zero-based
|
|
122
|
+
# Integer index.
|
|
123
|
+
def get_trace_span(trace_id, id: nil, name: nil, occurrence: "last")
|
|
124
|
+
validate_trace_id(trace_id)
|
|
125
|
+
raise ArgumentError, "Provide exactly one of id or name" if id.nil? == name.nil?
|
|
126
|
+
validate_span_id(id) unless id.nil?
|
|
127
|
+
if !name.nil? && (!name.is_a?(String) || name.empty?)
|
|
128
|
+
raise ArgumentError, "name must be a non-empty string"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
valid_occurrence = %w[first last].include?(occurrence) || (occurrence.is_a?(Integer) && occurrence >= 0)
|
|
132
|
+
unless valid_occurrence
|
|
133
|
+
raise ArgumentError, 'occurrence must be "first", "last", or a non-negative integer'
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@http_client.get_trace_span(trace_id, id:, name:, occurrence:)
|
|
137
|
+
end
|
|
138
|
+
|
|
118
139
|
# Execute a block inside a span context, sending trace data on completion.
|
|
119
140
|
# Called by Traceable, not intended for direct use.
|
|
120
141
|
def execute_span(trace_function_key:, span_name:, span_type:, function_name:, args:, kwargs:,
|
|
@@ -343,6 +364,14 @@ module Bitfab
|
|
|
343
364
|
|
|
344
365
|
private
|
|
345
366
|
|
|
367
|
+
def validate_trace_id(trace_id)
|
|
368
|
+
raise ArgumentError, "trace_id must be a valid Bitfab trace ID" unless trace_id.is_a?(String) && UUID_PATTERN.match?(trace_id)
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def validate_span_id(id)
|
|
372
|
+
raise ArgumentError, "id must be a valid Bitfab span ID" unless id.is_a?(String) && UUID_PATTERN.match?(id)
|
|
373
|
+
end
|
|
374
|
+
|
|
346
375
|
# Resolve the API key lazily, the first time a span actually needs it.
|
|
347
376
|
#
|
|
348
377
|
# The key is intentionally NOT read at construction: a client built when a
|
|
@@ -462,6 +491,7 @@ module Bitfab
|
|
|
462
491
|
end
|
|
463
492
|
|
|
464
493
|
payload = {
|
|
494
|
+
"id" => trace_id,
|
|
465
495
|
"type" => "sdk-function",
|
|
466
496
|
"source" => "ruby-sdk-function",
|
|
467
497
|
"traceFunctionKey" => trace_function_key,
|
|
@@ -492,7 +522,7 @@ module Bitfab
|
|
|
492
522
|
|
|
493
523
|
def send_span(trace_function_key:, trace_id:, span_id:, parent_span_id:,
|
|
494
524
|
span_name:, span_type:, function_name:, contexts:, prompt:, args:, kwargs:, result:, error:,
|
|
495
|
-
started_at:, ended_at:, test_run_id: nil, input_source_span_id: nil)
|
|
525
|
+
started_at:, ended_at:, test_run_id: nil, input_source_span_id: nil, mocked: false)
|
|
496
526
|
# If drop() was called on this trace, suppress the span PAYLOAD upload for
|
|
497
527
|
# every span that completes after the flag was set. The trace completion
|
|
498
528
|
# still rides out with dropped: true, so the server scrubs any sibling
|
|
@@ -540,6 +570,8 @@ module Bitfab
|
|
|
540
570
|
raw_span["input_source_span_id"] = input_source_span_id if input_source_span_id
|
|
541
571
|
|
|
542
572
|
payload = {
|
|
573
|
+
"id" => span_id,
|
|
574
|
+
"traceId" => trace_id,
|
|
543
575
|
"type" => "sdk-function",
|
|
544
576
|
"source" => "ruby-sdk-function",
|
|
545
577
|
"sourceTraceId" => trace_id,
|
|
@@ -547,6 +579,10 @@ module Bitfab
|
|
|
547
579
|
"rawSpan" => raw_span
|
|
548
580
|
}
|
|
549
581
|
payload["testRunId"] = test_run_id if test_run_id
|
|
582
|
+
# Flag spans served from the original trace's recorded output during a
|
|
583
|
+
# replay so the trace view can mark them (matches the Python and
|
|
584
|
+
# TypeScript SDKs).
|
|
585
|
+
payload["mocked"] = true if mocked
|
|
550
586
|
|
|
551
587
|
# A value that could only be captured as a placeholder makes the span
|
|
552
588
|
# non-replayable; record it on the payload's errors (matching the Python
|
|
@@ -644,7 +680,8 @@ module Bitfab
|
|
|
644
680
|
started_at:,
|
|
645
681
|
ended_at:,
|
|
646
682
|
test_run_id:,
|
|
647
|
-
input_source_span_id
|
|
683
|
+
input_source_span_id:,
|
|
684
|
+
mocked: true
|
|
648
685
|
)
|
|
649
686
|
# Mocked spans are always non-root (advance_mock_counter returns nil for
|
|
650
687
|
# root spans, so check_mock_replay never short-circuits them), so the
|
data/lib/bitfab/http_client.rb
CHANGED
|
@@ -80,7 +80,7 @@ module Bitfab
|
|
|
80
80
|
http.open_timeout = request_timeout
|
|
81
81
|
http.read_timeout = request_timeout
|
|
82
82
|
|
|
83
|
-
req = Net::HTTP::Get.new(uri.
|
|
83
|
+
req = Net::HTTP::Get.new(uri.request_uri, headers)
|
|
84
84
|
response = http.request(req)
|
|
85
85
|
|
|
86
86
|
unless response.is_a?(Net::HTTPSuccess)
|
|
@@ -140,6 +140,19 @@ module Bitfab
|
|
|
140
140
|
get("/api/sdk/externalSpans/#{span_id}", timeout: 30)
|
|
141
141
|
end
|
|
142
142
|
|
|
143
|
+
def get_trace_span(trace_id, id: nil, name: nil, occurrence: "last")
|
|
144
|
+
query = if id
|
|
145
|
+
{id:}
|
|
146
|
+
else
|
|
147
|
+
{name:, occurrence: occurrence.to_s}
|
|
148
|
+
end
|
|
149
|
+
encoded_trace_id = URI.encode_www_form_component(trace_id)
|
|
150
|
+
get(
|
|
151
|
+
"/api/sdk/traces/#{encoded_trace_id}/span?#{URI.encode_www_form(query)}",
|
|
152
|
+
timeout: 30
|
|
153
|
+
)["span"]
|
|
154
|
+
end
|
|
155
|
+
|
|
143
156
|
# Fetch the span tree rooted at an external span. Blocking GET request.
|
|
144
157
|
# Used by replay when a mock strategy is active so child spans can be
|
|
145
158
|
# matched against their historical outputs.
|
data/lib/bitfab/span_context.rb
CHANGED
data/lib/bitfab/version.rb
CHANGED
data/lib/bitfab.rb
CHANGED