@agentuity/runtime 1.0.7 → 1.0.9

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.
@@ -0,0 +1,108 @@
1
+ import { trace, TraceFlags, type Context } from '@opentelemetry/api';
2
+ import { TraceState } from '@opentelemetry/core';
3
+
4
+ /**
5
+ * Entries to set on the W3C tracestate header. Each key-value pair is added
6
+ * to the parent context's existing traceState (if any). Values that are
7
+ * `undefined` or empty strings are skipped.
8
+ */
9
+ export type TraceStateEntries = Record<string, string | undefined>;
10
+
11
+ /**
12
+ * Build a context whose span context carries an enriched W3C traceState.
13
+ *
14
+ * The returned context is intended to be passed as the **parent context**
15
+ * to `tracer.startActiveSpan(name, opts, enrichedCtx, fn)` or
16
+ * `tracer.startSpan(name, opts, enrichedCtx)`. Because the OTel SDK
17
+ * copies `traceState` from a *valid* parent span context into every new
18
+ * child span, the recording span that gets exported to OTLP will carry the
19
+ * enriched traceState — making it visible in backends like ClickHouse.
20
+ *
21
+ * ### How it works
22
+ *
23
+ * 1. If the supplied `parentContext` already contains a span with a valid
24
+ * span context (e.g. from an incoming `traceparent` header), we enrich
25
+ * that span context's traceState and wrap it in a `NonRecordingSpan`.
26
+ *
27
+ * 2. If there is **no** valid parent span (e.g. no incoming `traceparent`),
28
+ * we synthesise a minimal remote span context with a freshly generated
29
+ * traceId. The OTel SDK will treat this as a valid remote parent,
30
+ * inherit both the traceId **and** the traceState, and mark the new
31
+ * span as a continuation of that trace.
32
+ *
33
+ * @param parentContext The context to enrich (typically `context.active()`).
34
+ * @param entries Key-value pairs to merge into the traceState.
35
+ * @returns A new `Context` ready to be used as a parent for span creation.
36
+ */
37
+ export function enrichContextWithTraceState(
38
+ parentContext: Context,
39
+ entries: TraceStateEntries
40
+ ): Context {
41
+ const parentSpan = trace.getSpan(parentContext);
42
+ const parentSctx = parentSpan?.spanContext();
43
+
44
+ // Start from any existing traceState on the parent, or a fresh one.
45
+ let traceState = parentSctx?.traceState ?? new TraceState();
46
+
47
+ // Merge caller-supplied entries.
48
+ for (const [key, value] of Object.entries(entries)) {
49
+ if (value !== undefined && value !== '') {
50
+ traceState = traceState.set(key, value);
51
+ }
52
+ }
53
+
54
+ if (parentSctx && trace.isSpanContextValid(parentSctx)) {
55
+ // The parent already has a valid traceId/spanId (e.g. from an
56
+ // incoming request with `traceparent`). We just need to update
57
+ // its traceState.
58
+ return trace.setSpan(
59
+ parentContext,
60
+ trace.wrapSpanContext({
61
+ ...parentSctx,
62
+ traceState,
63
+ })
64
+ );
65
+ }
66
+
67
+ // No valid parent — synthesise a remote parent so the OTel SDK
68
+ // considers the span context valid and copies traceState to the child.
69
+ return trace.setSpan(
70
+ parentContext,
71
+ trace.wrapSpanContext({
72
+ traceId: generateTraceId(),
73
+ spanId: generateSpanId(),
74
+ traceFlags: TraceFlags.SAMPLED,
75
+ isRemote: true,
76
+ traceState,
77
+ })
78
+ );
79
+ }
80
+
81
+ // ── ID generation helpers ────────────────────────────────────────────
82
+
83
+ /**
84
+ * Generate a random 32-hex-char trace ID (16 bytes).
85
+ * Uses the Web Crypto API which is available in Bun and Node 20+.
86
+ */
87
+ export function generateTraceId(): string {
88
+ const bytes = new Uint8Array(16);
89
+ crypto.getRandomValues(bytes);
90
+ return hexFromBytes(bytes);
91
+ }
92
+
93
+ /**
94
+ * Generate a random 16-hex-char span ID (8 bytes).
95
+ */
96
+ export function generateSpanId(): string {
97
+ const bytes = new Uint8Array(8);
98
+ crypto.getRandomValues(bytes);
99
+ return hexFromBytes(bytes);
100
+ }
101
+
102
+ function hexFromBytes(bytes: Uint8Array): string {
103
+ let hex = '';
104
+ for (let i = 0; i < bytes.length; i++) {
105
+ hex += (bytes[i] as number).toString(16).padStart(2, '0');
106
+ }
107
+ return hex;
108
+ }
@@ -329,12 +329,12 @@ class LocalStream extends WritableStream implements Stream {
329
329
 
330
330
  async #persist(): Promise<void> {
331
331
  // Read buffered file
332
- let data = readFileSync(this.#tempFilePath);
332
+ let data: Buffer = readFileSync(this.#tempFilePath);
333
333
 
334
334
  // Optional: Apply compression if enabled
335
335
  if (this.#compressed) {
336
336
  const { gzipSync } = await import('node:zlib');
337
- data = gzipSync(data);
337
+ data = gzipSync(data) as Buffer;
338
338
  }
339
339
 
340
340
  // Update DB with finalized data