@kb-labs/agent-tracing 0.2.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.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # @kb-labs/agent-tracing
2
+
3
+ Execution tracing and observability for KB Labs agents. Writes crash-safe NDJSON trace files with privacy redaction and provides tools for loading and analyzing traces.
4
+
5
+ ## Features
6
+
7
+ - **Crash-safe NDJSON** — append-only writes, no data loss on crash
8
+ - **Incremental flushing** — traces available in real-time during execution
9
+ - **Privacy redaction** — strips API keys, tokens, personal paths
10
+ - **Trace indexing** — fast lookups by event type, tool name, iteration
11
+ - **Helper factories** — type-safe builders for all event types
12
+
13
+ ## Components
14
+
15
+ ### IncrementalTraceWriter
16
+
17
+ Main tracer for production. Writes events to NDJSON file with automatic flushing and indexing.
18
+
19
+ ```typescript
20
+ import { IncrementalTraceWriter } from '@kb-labs/agent-tracing';
21
+
22
+ const writer = new IncrementalTraceWriter({
23
+ outputPath: './traces/run-001.ndjson',
24
+ flushIntervalMs: 1000,
25
+ });
26
+
27
+ writer.write(traceAgentStart({ task, tier, maxIterations, toolCount }));
28
+ // ... agent execution ...
29
+ writer.write(traceAgentEnd({ success, summary, iterations, tokensUsed, durationMs }));
30
+
31
+ await writer.close();
32
+ ```
33
+
34
+ ### FileTracer
35
+
36
+ In-memory tracer for tests and development.
37
+
38
+ ### TraceLoader
39
+
40
+ Loads and validates existing NDJSON trace files for CLI analysis commands.
41
+
42
+ ```typescript
43
+ import { loadTrace } from '@kb-labs/agent-tracing';
44
+
45
+ const result = loadTrace('./traces/run-001.ndjson');
46
+ if (result.ok) {
47
+ console.log(`${result.events.length} events loaded`);
48
+ }
49
+ ```
50
+
51
+ ### PrivacyRedactor
52
+
53
+ Redacts sensitive data before persistence:
54
+ - API keys and tokens (`sk-...`, `Bearer ...`)
55
+ - Personal file paths (`/Users/name/...` → `~/...`)
56
+ - Environment variables with secrets
57
+
58
+ ### Trace Helpers
59
+
60
+ Factory functions for all trace event types:
61
+
62
+ ```typescript
63
+ import {
64
+ traceAgentStart,
65
+ traceToolStart,
66
+ traceToolEnd,
67
+ traceLLMEnd,
68
+ } from '@kb-labs/agent-tracing';
69
+ ```
70
+
71
+ ## Trace Format
72
+
73
+ Each line in an NDJSON file is a JSON object:
74
+
75
+ ```json
76
+ {"type":"agent:start","timestamp":"...","data":{"task":"Fix bug","tier":"medium"}}
77
+ {"type":"tool:start","timestamp":"...","data":{"toolName":"fs_read","input":{"path":"src/auth.ts"}}}
78
+ {"type":"tool:end","timestamp":"...","data":{"toolName":"fs_read","success":true,"durationMs":12}}
79
+ ```
80
+
81
+ Default location: `.kb/traces/incremental/`.
82
+
83
+ ## Dependencies
84
+
85
+ - `@kb-labs/agent-contracts` — event type definitions
86
+ - `@kb-labs/sdk` — platform SDK
@@ -0,0 +1,582 @@
1
+ import * as _kb_labs_agent_contracts from '@kb-labs/agent-contracts';
2
+ import { Tracer, DetailedTraceEntry, TraceEntry, IterationDetailEvent, LLMCallEvent, ToolExecutionEvent, MemorySnapshotEvent, DecisionPointEvent, SynthesisForcedTraceEvent, ErrorCapturedEvent, FactAddedEvent, ArchiveStoreEvent, SummarizationLLMCallEvent, SummarizationResultEvent } from '@kb-labs/agent-contracts';
3
+ import { LLMMessage, LLMToolCallResponse } from '@kb-labs/sdk';
4
+
5
+ /**
6
+ * Incremental Trace Writer - NDJSON append-only tracer with crash safety
7
+ *
8
+ * Design principle: reliability > speed.
9
+ * Every event is written synchronously to disk immediately.
10
+ * Even if the agent crashes mid-execution, all events up to the crash are on disk.
11
+ *
12
+ * Features:
13
+ * - NDJSON format (newline-delimited JSON) for append-only writes
14
+ * - Synchronous writes — zero event loss, even on crash
15
+ * - Privacy redaction on trace() call
16
+ * - Auto-cleanup (keep last 30 traces)
17
+ * - Index generation for fast CLI queries
18
+ */
19
+
20
+ /**
21
+ * Trace configuration interface
22
+ */
23
+ interface TraceConfig {
24
+ version: string;
25
+ enabled: boolean;
26
+ level: 'minimal' | 'standard' | 'detailed' | 'debug';
27
+ incremental: {
28
+ enabled: boolean;
29
+ flushIntervalMs: number;
30
+ maxBufferSize: number;
31
+ format: 'ndjson';
32
+ };
33
+ capture: {
34
+ prompts: boolean;
35
+ toolOutputs: boolean;
36
+ memorySnapshots: boolean;
37
+ decisions: boolean;
38
+ };
39
+ retention: {
40
+ maxTraces: number;
41
+ maxDays: number;
42
+ cleanupOnFinalize: boolean;
43
+ archiveOlderThan: number;
44
+ compressArchived: boolean;
45
+ };
46
+ privacy: {
47
+ redactSecrets: boolean;
48
+ redactPaths: boolean;
49
+ secretPatterns: string[];
50
+ pathReplacements: Record<string, string>;
51
+ };
52
+ storage: {
53
+ path: string;
54
+ indexPath: string;
55
+ };
56
+ }
57
+ /**
58
+ * Trace index for fast CLI queries
59
+ */
60
+ interface TraceIndex {
61
+ version: string;
62
+ taskId: string;
63
+ createdAt: string;
64
+ finalizedAt: string;
65
+ summary: {
66
+ totalEvents: number;
67
+ iterations: number;
68
+ status: 'success' | 'failed' | 'incomplete';
69
+ eventCounts: Record<string, number>;
70
+ };
71
+ timing: {
72
+ startedAt: string;
73
+ completedAt: string;
74
+ totalDurationMs: number;
75
+ };
76
+ cost: {
77
+ totalCost: number;
78
+ currency: 'USD';
79
+ };
80
+ errors: number;
81
+ /** Two-tier memory statistics (aggregated from memory:* events) */
82
+ memory?: {
83
+ totalFactsAdded: number;
84
+ totalArchiveStores: number;
85
+ summarizationRuns: number;
86
+ avgCompressionRatio: number;
87
+ avgNewFactRate: number;
88
+ finalFactSheetSize: number;
89
+ finalFactSheetTokens: number;
90
+ finalArchiveEntries: number;
91
+ finalArchiveUniqueFiles: number;
92
+ };
93
+ iterations: Array<{
94
+ iteration: number;
95
+ eventCount: number;
96
+ llmCalls: number;
97
+ toolCalls: number;
98
+ }>;
99
+ }
100
+ /**
101
+ * Default trace configuration
102
+ */
103
+ declare const DEFAULT_TRACE_CONFIG: TraceConfig;
104
+ /**
105
+ * Incremental Trace Writer - crash-safe NDJSON tracer
106
+ */
107
+ declare class IncrementalTraceWriter implements Tracer {
108
+ private seq;
109
+ private filepath;
110
+ private indexPath;
111
+ private config;
112
+ private taskId;
113
+ private startTime;
114
+ constructor(taskId: string, config?: Partial<TraceConfig>, outputDir?: string);
115
+ /**
116
+ * Record a trace entry — writes synchronously to disk.
117
+ *
118
+ * Every call = one appendFileSync. No buffering, no async, no lost events.
119
+ * If the agent crashes on iteration 5, you have all events from iterations 1-5.
120
+ */
121
+ trace(entry: any): void;
122
+ /**
123
+ * Get all trace entries (reads from NDJSON file to avoid memory leak)
124
+ * Returns TraceEntry[] for backward compatibility, but actual format is DetailedTraceEntry[]
125
+ */
126
+ getEntries(): any[];
127
+ /**
128
+ * Save trace to file (backward compat — no-op, already written synchronously)
129
+ */
130
+ save(_filePath: string): Promise<void>;
131
+ /**
132
+ * Clear all entries
133
+ */
134
+ clear(): void;
135
+ /**
136
+ * Finalize trace (generate index, cleanup old traces)
137
+ */
138
+ finalize(): Promise<void>;
139
+ /**
140
+ * Create index file for fast CLI queries
141
+ */
142
+ createIndex(): Promise<void>;
143
+ /**
144
+ * Cleanup old traces (keep last N traces)
145
+ */
146
+ private cleanupOldTraces;
147
+ /**
148
+ * Redact sensitive data from entry using optimized privacy-redactor
149
+ *
150
+ * Uses shallow clone optimization - only clones objects that need redaction,
151
+ * not the entire trace event tree. Returns original if no secrets found.
152
+ */
153
+ private redact;
154
+ /**
155
+ * Calculate index statistics from trace entries
156
+ */
157
+ private calculateIndexStatistics;
158
+ /**
159
+ * Ensure directory exists
160
+ */
161
+ private ensureDirectoryExists;
162
+ }
163
+
164
+ /**
165
+ * File-based tracer that saves execution traces to JSON files
166
+ */
167
+
168
+ type AnyEntry = Omit<DetailedTraceEntry, 'seq' | 'timestamp'>;
169
+ /**
170
+ * File tracer implementation
171
+ */
172
+ declare class FileTracer implements Tracer {
173
+ private entries;
174
+ private taskId;
175
+ private sessionId?;
176
+ constructor(taskId: string, sessionId?: string);
177
+ /**
178
+ * Record a trace entry
179
+ */
180
+ trace(entry: AnyEntry): void;
181
+ /**
182
+ * Get all trace entries
183
+ */
184
+ getEntries(): TraceEntry[];
185
+ /**
186
+ * Save trace to file
187
+ */
188
+ save(filePath: string): Promise<void>;
189
+ /**
190
+ * Clear all entries
191
+ */
192
+ clear(): void;
193
+ /**
194
+ * Get trace summary statistics
195
+ */
196
+ getSummary(): {
197
+ totalEntries: number;
198
+ llmCalls: number;
199
+ toolCalls: number;
200
+ totalDuration: number;
201
+ avgLLMDuration: number;
202
+ avgToolDuration: number;
203
+ };
204
+ }
205
+
206
+ /**
207
+ * TraceLoader — loads and validates NDJSON trace files for CLI commands.
208
+ *
209
+ * Centralizes the logic duplicated across all trace commands:
210
+ * - taskId format validation (prevent path traversal)
211
+ * - file existence check
212
+ * - file size guard (prevent memory exhaustion)
213
+ * - NDJSON parsing with graceful line-error handling
214
+ */
215
+
216
+ declare const TRACE_DIR_RELATIVE: string;
217
+ type TraceLoadError = {
218
+ kind: 'invalid_task_id';
219
+ message: string;
220
+ } | {
221
+ kind: 'not_found';
222
+ taskId: string;
223
+ } | {
224
+ kind: 'too_large';
225
+ sizeBytes: number;
226
+ } | {
227
+ kind: 'empty';
228
+ taskId: string;
229
+ } | {
230
+ kind: 'io_error';
231
+ message: string;
232
+ };
233
+ type TraceLoadResult = {
234
+ ok: true;
235
+ events: DetailedTraceEntry[];
236
+ taskId: string;
237
+ filePath: string;
238
+ } | {
239
+ ok: false;
240
+ error: TraceLoadError;
241
+ };
242
+ /**
243
+ * Load and parse a trace file by taskId.
244
+ *
245
+ * @param taskId - The task ID (validated against alphanumeric + hyphens/underscores)
246
+ * @param workingDir - Base directory to resolve `.kb/traces/incremental/` from (default: process.cwd())
247
+ */
248
+ declare function loadTrace(taskId: string | undefined, workingDir?: string): Promise<TraceLoadResult>;
249
+ /**
250
+ * Format a TraceLoadError into a human-readable string for CLI output.
251
+ */
252
+ declare function formatTraceLoadError(error: TraceLoadError): string;
253
+
254
+ /**
255
+ * Create iteration:detail event
256
+ */
257
+ declare function createIterationDetailEvent(params: {
258
+ iteration: number;
259
+ maxIterations: number;
260
+ mode: 'instant' | 'auto' | 'thinking';
261
+ temperature: number;
262
+ availableTools: string[];
263
+ messages: LLMMessage[];
264
+ totalTokens: number;
265
+ }): Omit<IterationDetailEvent, 'seq' | 'timestamp'>;
266
+ /**
267
+ * Create llm:call event
268
+ */
269
+ declare function createLLMCallEvent(params: {
270
+ iteration: number;
271
+ model: string;
272
+ temperature: number;
273
+ maxTokens: number;
274
+ tools: string[];
275
+ response: LLMToolCallResponse;
276
+ startTime: number;
277
+ endTime: number;
278
+ }): Omit<LLMCallEvent, 'seq' | 'timestamp'>;
279
+ /**
280
+ * Create tool:execution event
281
+ */
282
+ declare function createToolExecutionEvent(params: {
283
+ iteration: number;
284
+ toolName: string;
285
+ callId: string;
286
+ input: unknown;
287
+ output: {
288
+ success: boolean;
289
+ result?: unknown;
290
+ error?: {
291
+ message: string;
292
+ code?: string;
293
+ stack?: string;
294
+ };
295
+ };
296
+ startTime: number;
297
+ endTime: number;
298
+ metadata?: Record<string, unknown>;
299
+ }): Omit<ToolExecutionEvent, 'seq' | 'timestamp'>;
300
+ /**
301
+ * Create memory:snapshot event
302
+ */
303
+ declare function createMemorySnapshotEvent(params: {
304
+ iteration: number;
305
+ conversationHistory: number;
306
+ userPreferences: Record<string, unknown>;
307
+ facts: string[];
308
+ findings: string[];
309
+ filesRead: string[];
310
+ searchesMade: number;
311
+ toolsUsed: Record<string, number>;
312
+ }): Omit<MemorySnapshotEvent, 'seq' | 'timestamp'>;
313
+ /**
314
+ * Create decision:point event
315
+ */
316
+ declare function createDecisionPointEvent(params: {
317
+ iteration: number;
318
+ decision: 'tool_selection' | 'stopping_condition' | 'synthesis';
319
+ toolSelection?: {
320
+ chosenTool: string;
321
+ reasoning: string;
322
+ alternatives: Array<{
323
+ tool: string;
324
+ reason: string;
325
+ }>;
326
+ };
327
+ stoppingCondition?: {
328
+ shouldStop: boolean;
329
+ reason: string;
330
+ };
331
+ }): Omit<DecisionPointEvent, 'seq' | 'timestamp'>;
332
+ /**
333
+ * Create synthesis:forced event
334
+ */
335
+ declare function createSynthesisForcedEvent(params: {
336
+ iteration: number;
337
+ reason: 'last_iteration' | 'max_iterations' | 'no_tool_call' | 'user_request';
338
+ lastIteration: number;
339
+ lastToolCall?: string;
340
+ synthesisPrompt: string;
341
+ synthesisResponse: {
342
+ content: string;
343
+ tokens: number;
344
+ durationMs: number;
345
+ };
346
+ }): Omit<SynthesisForcedTraceEvent, 'seq' | 'timestamp'>;
347
+ /**
348
+ * Create error:captured event
349
+ */
350
+ declare function createErrorCapturedEvent(params: {
351
+ iteration: number;
352
+ error: Error;
353
+ lastLLMCall?: {
354
+ request: unknown;
355
+ response: unknown;
356
+ durationMs: number;
357
+ };
358
+ lastToolCall?: {
359
+ name: string;
360
+ input: unknown;
361
+ output?: unknown;
362
+ error?: string;
363
+ };
364
+ currentMessages: LLMMessage[];
365
+ memoryState: {
366
+ filesRead: string[];
367
+ searchesMade: number;
368
+ };
369
+ availableTools: string[];
370
+ agentStack: {
371
+ currentPhase?: string;
372
+ currentStep?: string;
373
+ iterationHistory: number[];
374
+ };
375
+ }): Omit<ErrorCapturedEvent, 'seq' | 'timestamp'>;
376
+ /**
377
+ * Create prompt:diff event
378
+ */
379
+ declare function createPromptDiffEvent(params: {
380
+ iteration: number;
381
+ messagesAdded: number;
382
+ messagesRemoved: number;
383
+ totalMessages: number;
384
+ changes: Array<{
385
+ type: 'added' | 'removed' | 'modified';
386
+ role: 'system' | 'user' | 'assistant';
387
+ contentPreview: string;
388
+ index: number;
389
+ }>;
390
+ tokensBefore: number;
391
+ tokensAfter: number;
392
+ }): Omit<_kb_labs_agent_contracts.PromptDiffEvent, 'seq' | 'timestamp'>;
393
+ /**
394
+ * Create tool:filter event
395
+ */
396
+ declare function createToolFilterEvent(params: {
397
+ iteration: number;
398
+ beforeTools: string[];
399
+ afterTools: string[];
400
+ filtered: Array<{
401
+ name: string;
402
+ reason: 'last_iteration' | 'mode_restriction' | 'tier_restriction' | 'custom';
403
+ explanation: string;
404
+ }>;
405
+ }): Omit<_kb_labs_agent_contracts.ToolFilterEvent, 'seq' | 'timestamp'>;
406
+ /**
407
+ * Create context:trim event
408
+ */
409
+ declare function createContextTrimEvent(params: {
410
+ iteration: number;
411
+ trigger: 'max_tokens' | 'max_messages' | 'manual';
412
+ messageCountBefore: number;
413
+ messageCountAfter: number;
414
+ tokensBefore: number;
415
+ tokensAfter: number;
416
+ messagesRemoved: number;
417
+ tokensRemoved: number;
418
+ contentPreview: string;
419
+ strategy: 'sliding_window' | 'summarization' | 'importance_based';
420
+ }): Omit<_kb_labs_agent_contracts.ContextTrimEvent, 'seq' | 'timestamp'>;
421
+ /**
422
+ * Create stopping:analysis event
423
+ */
424
+ declare function createStoppingAnalysisEvent(params: {
425
+ iteration: number;
426
+ conditions: {
427
+ maxIterationsReached: boolean;
428
+ timeoutReached: boolean;
429
+ foundTarget: boolean;
430
+ sufficientContext: boolean;
431
+ diminishingReturns: boolean;
432
+ userInterrupt: boolean;
433
+ error: boolean;
434
+ };
435
+ reasoning: string;
436
+ iterationsUsed: number;
437
+ iterationsRemaining: number;
438
+ timeElapsedMs: number;
439
+ timeRemainingMs?: number;
440
+ toolCallsInLast3Iterations: number;
441
+ confidenceScore?: number;
442
+ }): Omit<_kb_labs_agent_contracts.StoppingAnalysisEvent, 'seq' | 'timestamp'>;
443
+ /**
444
+ * Create llm:validation event
445
+ */
446
+ declare function createLLMValidationEvent(params: {
447
+ iteration: number;
448
+ stopReason: 'tool_use' | 'end_turn' | 'max_tokens' | 'stop_sequence';
449
+ isValid: boolean;
450
+ hasContent: boolean;
451
+ hasToolCalls: boolean;
452
+ toolCallsValid: boolean;
453
+ jsonParseable: boolean;
454
+ schemaValid: boolean;
455
+ issues: Array<{
456
+ severity: 'error' | 'warning' | 'info';
457
+ check: string;
458
+ message: string;
459
+ recovery?: string;
460
+ }>;
461
+ }): Omit<_kb_labs_agent_contracts.LLMValidationEvent, 'seq' | 'timestamp'>;
462
+ /**
463
+ * Create memory:fact_added event
464
+ */
465
+ declare function createFactAddedEvent(params: {
466
+ iteration: number;
467
+ fact: {
468
+ id: string;
469
+ category: string;
470
+ fact: string;
471
+ confidence: number;
472
+ source: string;
473
+ merged: boolean;
474
+ superseded?: string;
475
+ };
476
+ factSheetStats: {
477
+ totalFacts: number;
478
+ estimatedTokens: number;
479
+ byCategory: Record<string, number>;
480
+ };
481
+ }): Omit<FactAddedEvent, 'seq' | 'timestamp'>;
482
+ /**
483
+ * Create memory:archive_store event
484
+ */
485
+ declare function createArchiveStoreEvent(params: {
486
+ iteration: number;
487
+ entry: {
488
+ id: string;
489
+ toolName: string;
490
+ filePath?: string;
491
+ outputLength: number;
492
+ estimatedTokens: number;
493
+ keyFactsExtracted: number;
494
+ };
495
+ archiveStats: {
496
+ totalEntries: number;
497
+ totalChars: number;
498
+ uniqueFiles: number;
499
+ evicted: number;
500
+ };
501
+ }): Omit<ArchiveStoreEvent, 'seq' | 'timestamp'>;
502
+ /**
503
+ * Create memory:summarization_llm_call event.
504
+ * Records the raw LLM interaction for fact extraction debugging.
505
+ */
506
+ declare function createSummarizationLLMCallEvent(params: {
507
+ iteration: number;
508
+ prompt: string;
509
+ rawResponse: string;
510
+ parseSuccess: boolean;
511
+ parseError?: string;
512
+ durationMs: number;
513
+ outputTokens: number;
514
+ }): Omit<SummarizationLLMCallEvent, 'seq' | 'timestamp'>;
515
+ /**
516
+ * Create memory:summarization_result event
517
+ */
518
+ declare function createSummarizationResultEvent(params: {
519
+ iteration: number;
520
+ input: {
521
+ iterationRange: [number, number];
522
+ messagesCount: number;
523
+ inputChars: number;
524
+ inputTokens: number;
525
+ };
526
+ output: {
527
+ factsExtracted: number;
528
+ factsByCategory: Record<string, number>;
529
+ outputTokens: number;
530
+ llmDurationMs: number;
531
+ };
532
+ delta: {
533
+ factSheetBefore: number;
534
+ factSheetAfter: number;
535
+ tokensBefore: number;
536
+ tokensAfter: number;
537
+ newFacts: number;
538
+ mergedFacts: number;
539
+ evictedFacts: number;
540
+ };
541
+ efficiency: {
542
+ compressionRatio: number;
543
+ factDensity: number;
544
+ newFactRate: number;
545
+ };
546
+ }): Omit<SummarizationResultEvent, 'seq' | 'timestamp'>;
547
+
548
+ /**
549
+ * Privacy redaction for trace events
550
+ *
551
+ * Uses shallow clone optimization - only clones objects that need redaction,
552
+ * not the entire trace event tree.
553
+ */
554
+
555
+ /**
556
+ * Redact secrets from a string
557
+ */
558
+ declare function redactSecretsFromString(str: string, patterns?: RegExp[]): string;
559
+ /**
560
+ * Redact file paths (replace absolute paths with relative)
561
+ */
562
+ declare function redactPaths(str: string, replacements: Record<string, string>): string;
563
+ /**
564
+ * Redact secrets from unknown value (recursive shallow clone)
565
+ *
566
+ * Only clones objects/arrays that contain secrets.
567
+ * Primitives and clean objects are returned as-is (no clone).
568
+ */
569
+ declare function redactValue(value: unknown, config: TraceConfig['privacy'], depth?: number): unknown;
570
+ /**
571
+ * Redact secrets from a trace event (shallow clone optimization)
572
+ *
573
+ * Only clones parts of the event that need redaction.
574
+ * Returns original event if no redaction needed.
575
+ */
576
+ declare function redactTraceEvent(event: DetailedTraceEntry, config: TraceConfig['privacy']): DetailedTraceEntry;
577
+ /**
578
+ * Create default privacy config
579
+ */
580
+ declare function createDefaultPrivacyConfig(): TraceConfig['privacy'];
581
+
582
+ export { DEFAULT_TRACE_CONFIG, FileTracer, IncrementalTraceWriter, TRACE_DIR_RELATIVE, type TraceConfig, type TraceIndex, type TraceLoadError, type TraceLoadResult, createArchiveStoreEvent, createContextTrimEvent, createDecisionPointEvent, createDefaultPrivacyConfig, createErrorCapturedEvent, createFactAddedEvent, createIterationDetailEvent, createLLMCallEvent, createLLMValidationEvent, createMemorySnapshotEvent, createPromptDiffEvent, createStoppingAnalysisEvent, createSummarizationLLMCallEvent, createSummarizationResultEvent, createSynthesisForcedEvent, createToolExecutionEvent, createToolFilterEvent, formatTraceLoadError, loadTrace, redactPaths, redactSecretsFromString, redactTraceEvent, redactValue };