@hue-run/sdk 0.18.0 → 0.18.2
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.
- package/CLI.md +130 -8
- package/EVALUATIONS.md +7 -4
- package/README.md +86 -22
- package/dist/attachment.d.ts +51 -7
- package/dist/attachment.js +141 -33
- package/dist/blobs.d.ts +22 -5
- package/dist/blobs.js +187 -72
- package/dist/cli/import.d.ts +35 -0
- package/dist/cli/import.js +692 -0
- package/dist/cli/langfuse.d.ts +309 -0
- package/dist/cli/langfuse.js +1075 -0
- package/dist/client.d.ts +9 -4
- package/dist/client.js +46 -15
- package/dist/evals/client.d.ts +7 -2
- package/dist/evals/client.js +20 -4
- package/dist/evals/files.js +100 -12
- package/dist/evals/media.d.ts +5 -1
- package/dist/evals/media.js +15 -3
- package/dist/evals/types.d.ts +4 -3
- package/dist/inline-files.d.ts +16 -6
- package/dist/inline-files.js +18 -14
- package/dist/json-edits.js +26 -7
- package/dist/large-media.d.ts +106 -0
- package/dist/large-media.js +414 -0
- package/dist/setup/cli.js +7 -3
- package/dist/snapshot.d.ts +2 -0
- package/dist/snapshot.js +19 -1
- package/dist/transport.d.ts +4 -0
- package/dist/transport.js +36 -16
- package/dist/types.d.ts +10 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/transport.js
CHANGED
|
@@ -6,7 +6,8 @@ import { LogsExporterMetricsHelper, ProtobufLogsSerializer, ProtobufTraceSeriali
|
|
|
6
6
|
import { BatchSpanProcessor, } from "@opentelemetry/sdk-trace";
|
|
7
7
|
import { BatchLogRecordProcessor, } from "@opentelemetry/sdk-logs";
|
|
8
8
|
import { isInsecureOrigin, REDACTION_CONTEXT_UNITS, validateOptions } from "./config.js";
|
|
9
|
-
import { BLOBS_KEY, MAX_BLOB_ENTRIES, blobEntry, countFallback, BlobUploader, FALLBACK_MESSAGES, fallbackAttributes, fallbackRecord, MAX_HELD_BLOB_BYTES, newTally, mediaKey, offloadAttributes, offloadRecord, uploadBudgetMillis, } from "./blobs.js";
|
|
9
|
+
import { BLOBS_KEY, MAX_BLOB_ENTRIES, blobEntry, countFallback, BlobUploader, FALLBACK_MESSAGES, fallbackAttributes, fallbackRecord, heldBytesOf, MAX_HELD_BLOB_BYTES, newTally, mediaKey, offloadAttributes, offloadRecord, sizeOf, uploadBudgetMillis, } from "./blobs.js";
|
|
10
|
+
import { isByteSource } from "./large-media.js";
|
|
10
11
|
import { advertisedLimits, BATCH_TARGET_BYTES, DEFAULT_RECEIVER_LIMITS, fitsWithoutCompression, } from "./limits.js";
|
|
11
12
|
import { announcesLiveSpan, LIVE_SPAN_INTERVAL_MILLIS, MAX_LIVE_SPANS, pendingPlaceholder, PLACEHOLDERS_HEADER, withoutPlaceholderMarkers, } from "./live-spans.js";
|
|
12
13
|
import { estimateRecordBytes, spanSource } from "./safety.js";
|
|
@@ -184,6 +185,9 @@ export class HueTransport {
|
|
|
184
185
|
* over the request limit), reported on the trace's root span as `hue.sdk.dropped_records` when
|
|
185
186
|
* the root is exported, so Hue reads the trace as incomplete by that many records. */
|
|
186
187
|
droppedByTrace = new Map();
|
|
188
|
+
/** Whether a trace's root carries `hue.sdk.dropped_records`; off for a replay of recorded
|
|
189
|
+
* spans, which must send the same root on every run. */
|
|
190
|
+
marksDroppedRecords = true;
|
|
187
191
|
instrumentationFailures = 0;
|
|
188
192
|
diagnosticPending = false;
|
|
189
193
|
lastDiagnosticAt = -Infinity;
|
|
@@ -215,6 +219,8 @@ export class HueTransport {
|
|
|
215
219
|
admissionDigests = new WeakMap();
|
|
216
220
|
// The span's own messages each admitted span inspected, or left to export to inspect.
|
|
217
221
|
admissionInspected = new WeakMap();
|
|
222
|
+
// The span's own values each admitted span held whole past the inspection bounds.
|
|
223
|
+
admissionLarge = new WeakMap();
|
|
218
224
|
/** Uploads values over the inline limit apart from their spans; absent when disabled. */
|
|
219
225
|
uploader;
|
|
220
226
|
/** Bytes of values over the inline limit queued spans hold whole for upload, and each span's. */
|
|
@@ -242,9 +248,12 @@ export class HueTransport {
|
|
|
242
248
|
this.liveSpans = this.options.enabled !== false && this.options.liveSpans;
|
|
243
249
|
this.announcesLiveSpans = this.liveSpans;
|
|
244
250
|
this.traceExporter = new ReportingExporter(this, "traces", ProtobufTraceSerializer, TraceExporterMetricsHelper, (span, cache, offload) => {
|
|
245
|
-
// Export inspects only the messages admission inspected within the record's allowance
|
|
246
|
-
|
|
251
|
+
// Export inspects only the messages admission inspected within the record's allowance,
|
|
252
|
+
// and reads in place the values it held whole past the inspection bounds.
|
|
253
|
+
if (offload) {
|
|
247
254
|
offload.inspected = this.admissionInspected.get(span);
|
|
255
|
+
offload.large = this.admissionLarge.get(span);
|
|
256
|
+
}
|
|
248
257
|
return redactSpan(span, this.options, cache, {
|
|
249
258
|
valueBytes: this.limits.valueBytes,
|
|
250
259
|
cut: this.admissionCuts.get(span),
|
|
@@ -305,7 +314,7 @@ export class HueTransport {
|
|
|
305
314
|
if (!queued) {
|
|
306
315
|
const tally = newTally();
|
|
307
316
|
for (const file of this.mediaAttachments(span))
|
|
308
|
-
if (file.bytes
|
|
317
|
+
if (sizeOf(file.bytes))
|
|
309
318
|
countFallback(tally, "budget", span.spanContext().traceId);
|
|
310
319
|
this.reportOffload(tally);
|
|
311
320
|
this.releaseMedia(span);
|
|
@@ -404,6 +413,8 @@ export class HueTransport {
|
|
|
404
413
|
this.admissionDigests.set(snapshot.record, snapshot.digested);
|
|
405
414
|
if (signal === "traces")
|
|
406
415
|
this.admissionInspected.set(snapshot.record, snapshot.inspected);
|
|
416
|
+
if (snapshot.large.size)
|
|
417
|
+
this.admissionLarge.set(snapshot.record, snapshot.large);
|
|
407
418
|
if (snapshot.held) {
|
|
408
419
|
this.heldBytes += snapshot.held;
|
|
409
420
|
this.held.set(snapshot.record, snapshot.held);
|
|
@@ -531,7 +542,7 @@ export class HueTransport {
|
|
|
531
542
|
}
|
|
532
543
|
/** @internal Retain a defensive copy within the existing held-value budget. */
|
|
533
544
|
stageMedia(span, file) {
|
|
534
|
-
if (this.closed || !this.offloadsValues() || file
|
|
545
|
+
if (this.closed || !this.offloadsValues() || (file && sizeOf(file.bytes) === 0))
|
|
535
546
|
return true;
|
|
536
547
|
if (!file) {
|
|
537
548
|
const tally = newTally();
|
|
@@ -549,16 +560,18 @@ export class HueTransport {
|
|
|
549
560
|
const files = this.media.get(identity) ?? [];
|
|
550
561
|
if (files.length >= 64 ||
|
|
551
562
|
(!this.media.has(identity) && this.media.size >= 2048) ||
|
|
552
|
-
this.heldBytes + file.bytes
|
|
563
|
+
this.heldBytes + heldBytesOf(file.bytes) > MAX_HELD_BLOB_BYTES) {
|
|
553
564
|
this.uploadFallbacks++;
|
|
554
565
|
this.issue("traces", "warning", 1, "File bytes did not fit the SDK's upload budget; their hue.file metadata was recorded", undefined, [span.spanContext().traceId]);
|
|
555
566
|
return false;
|
|
556
567
|
}
|
|
557
|
-
|
|
568
|
+
// A file read from disk as it is uploaded holds no bytes; bytes are copied, so a later change
|
|
569
|
+
// to the caller's buffer cannot alter what was recorded.
|
|
570
|
+
const bytes = isByteSource(file.bytes) ? file.bytes : Uint8Array.from(file.bytes);
|
|
558
571
|
files.push({ ...file, bytes });
|
|
559
572
|
this.media.set(identity, files);
|
|
560
573
|
this.ownMedia(span, identity);
|
|
561
|
-
this.heldBytes += bytes
|
|
574
|
+
this.heldBytes += heldBytesOf(bytes);
|
|
562
575
|
return true;
|
|
563
576
|
}
|
|
564
577
|
/**
|
|
@@ -576,7 +589,7 @@ export class HueTransport {
|
|
|
576
589
|
const kept = previous.filter((file) => {
|
|
577
590
|
if (file.attribute !== attribute)
|
|
578
591
|
return true;
|
|
579
|
-
this.heldBytes -= file.bytes
|
|
592
|
+
this.heldBytes -= heldBytesOf(file.bytes);
|
|
580
593
|
return false;
|
|
581
594
|
});
|
|
582
595
|
if (kept.length)
|
|
@@ -586,7 +599,7 @@ export class HueTransport {
|
|
|
586
599
|
}
|
|
587
600
|
const tally = newTally();
|
|
588
601
|
for (const file of files) {
|
|
589
|
-
if (!file.bytes
|
|
602
|
+
if (!sizeOf(file.bytes))
|
|
590
603
|
continue;
|
|
591
604
|
const refused = this.uploader?.refusal();
|
|
592
605
|
if (!this.holdsValues() || refused) {
|
|
@@ -597,14 +610,14 @@ export class HueTransport {
|
|
|
597
610
|
const staged = this.media.get(identity) ?? [];
|
|
598
611
|
if (staged.length >= MAX_BLOB_ENTRIES ||
|
|
599
612
|
(!this.media.has(identity) && this.media.size >= 2048) ||
|
|
600
|
-
this.heldBytes + file.bytes
|
|
613
|
+
this.heldBytes + heldBytesOf(file.bytes) > MAX_HELD_BLOB_BYTES) {
|
|
601
614
|
countFallback(tally, "budget", traceId);
|
|
602
615
|
continue;
|
|
603
616
|
}
|
|
604
617
|
// Attachment bytes are the attachment's own copy: held as they are.
|
|
605
618
|
staged.push({ ...file, attribute });
|
|
606
619
|
this.media.set(identity, staged);
|
|
607
|
-
this.heldBytes += file.bytes
|
|
620
|
+
this.heldBytes += heldBytesOf(file.bytes);
|
|
608
621
|
this.ownMedia(span, identity);
|
|
609
622
|
}
|
|
610
623
|
if (tally.fallbacks.size)
|
|
@@ -621,7 +634,7 @@ export class HueTransport {
|
|
|
621
634
|
const tally = newTally();
|
|
622
635
|
const staged = [];
|
|
623
636
|
for (const file of files) {
|
|
624
|
-
if (!file.bytes
|
|
637
|
+
if (!sizeOf(file.bytes))
|
|
625
638
|
continue;
|
|
626
639
|
const refused = this.uploader?.refusal();
|
|
627
640
|
if (!this.holdsValues() || refused)
|
|
@@ -648,7 +661,7 @@ export class HueTransport {
|
|
|
648
661
|
if (!pending)
|
|
649
662
|
return;
|
|
650
663
|
this.logParts.delete(body);
|
|
651
|
-
const size = pending.files.reduce((total, file) => total + file.bytes
|
|
664
|
+
const size = pending.files.reduce((total, file) => total + heldBytesOf(file.bytes), 0);
|
|
652
665
|
if (this.heldBytes + size > MAX_HELD_BLOB_BYTES) {
|
|
653
666
|
const tally = newTally();
|
|
654
667
|
for (const _file of pending.files)
|
|
@@ -711,7 +724,7 @@ export class HueTransport {
|
|
|
711
724
|
if (!files)
|
|
712
725
|
return;
|
|
713
726
|
for (const file of files)
|
|
714
|
-
this.heldBytes -= file.bytes
|
|
727
|
+
this.heldBytes -= heldBytesOf(file.bytes);
|
|
715
728
|
this.media.delete(identity);
|
|
716
729
|
}
|
|
717
730
|
sweepMedia() {
|
|
@@ -822,13 +835,20 @@ export class HueTransport {
|
|
|
822
835
|
* (`consumeDroppedRecords`): a root written again under retry says the same, and a root whose
|
|
823
836
|
* request failed has not told Hue, so its count is not forgotten with it. */
|
|
824
837
|
withDroppedRecords(span) {
|
|
825
|
-
if (span.parentSpanContext)
|
|
838
|
+
if (span.parentSpanContext || !this.marksDroppedRecords)
|
|
826
839
|
return span;
|
|
827
840
|
const count = this.droppedByTrace.get(span.spanContext().traceId);
|
|
828
841
|
if (!count)
|
|
829
842
|
return span;
|
|
830
843
|
return { ...span, attributes: { ...span.attributes, [DROPPED_RECORDS_KEY]: count } };
|
|
831
844
|
}
|
|
845
|
+
/** @internal For an import that replays recorded spans: roots never carry the count of
|
|
846
|
+
* records this run did not deliver, so a later run that delivers them sends each root as it
|
|
847
|
+
* was first sent, which Hue keeps as an exact replay. The losses are still counted and
|
|
848
|
+
* reported. */
|
|
849
|
+
omitDroppedRecords() {
|
|
850
|
+
this.marksDroppedRecords = false;
|
|
851
|
+
}
|
|
832
852
|
/** @internal Exporter callback: these counts reached Hue on their traces' roots. Only what a
|
|
833
853
|
* root carried is forgotten: a record lost while its request was in flight is still counted. */
|
|
834
854
|
consumeDroppedRecords(counts) {
|
package/dist/types.d.ts
CHANGED
|
@@ -256,11 +256,19 @@ export interface FileRecord {
|
|
|
256
256
|
mediaType: string;
|
|
257
257
|
/** Hex SHA-256 of the file's bytes; computed from `data` when omitted. */
|
|
258
258
|
sha256?: string;
|
|
259
|
-
/** Upload
|
|
259
|
+
/** Upload the file's bytes (`data`, or the file at `path`) on this span when content capture is
|
|
260
|
+
* enabled. Defaults to false. */
|
|
260
261
|
upload?: boolean;
|
|
261
262
|
/** The file's bytes, hashed and measured locally by default; a string is hashed as UTF-8.
|
|
262
|
-
* Data larger than 25 MiB
|
|
263
|
+
* Data larger than 25 MiB, which would be held in memory until it is uploaded, is omitted and
|
|
264
|
+
* counted as an instrumentation failure. Give `data` or `path`, not both. */
|
|
263
265
|
data?: Uint8Array | string;
|
|
266
|
+
/** A file to hash and measure locally (Node.js file system) instead of `data`. Up to 25 MiB it is
|
|
267
|
+
* read now, as `data` is. A larger regular file, up to Hue's 1 GB upload limit, is hashed now a
|
|
268
|
+
* slice at a time and, with `upload: true`, read again from disk when it is uploaded: it must
|
|
269
|
+
* stay unchanged until the client flushes, and is uploaded only if it still has the size and
|
|
270
|
+
* SHA-256 it was recorded with (otherwise it counts as an upload fallback). */
|
|
271
|
+
path?: string;
|
|
264
272
|
/** Size in bytes; computed from `data` when omitted. */
|
|
265
273
|
byteSize?: number;
|
|
266
274
|
/** File name, recorded as `hue.file.name` only when `captureContent` is true. */
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Package version shared by the instrumentation scope and the export User-Agent. */
|
|
2
|
-
export declare const sdkVersion = "0.18.
|
|
2
|
+
export declare const sdkVersion = "0.18.2";
|
package/dist/version.js
CHANGED