From ae49479c6cca683479520c50aec753529f8fe698 Mon Sep 17 00:00:00 2001 From: rcholic Date: Sat, 3 Jan 2026 18:19:51 -0800 Subject: [PATCH 1/2] hook for redacting PII --- src/tracing/tracer-factory.ts | 18 ++++++++++++++++-- src/tracing/tracer.ts | 30 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/tracing/tracer-factory.ts b/src/tracing/tracer-factory.ts index 302c5ff1..36d598c7 100644 --- a/src/tracing/tracer-factory.ts +++ b/src/tracing/tracer-factory.ts @@ -197,6 +197,7 @@ function httpPost( * @param options.agentType - Type of agent running (e.g., "SentienceAgent", "CustomAgent") * @param options.llmModel - LLM model used (e.g., "gpt-4-turbo", "claude-3-5-sonnet") * @param options.startUrl - Starting URL of the agent run (e.g., "https://amazon.com") + * @param options.screenshotProcessor - Optional function to process screenshots before upload. Takes base64 string, returns processed base64 string. Useful for PII redaction or custom image processing. * @returns Tracer configured with appropriate sink * * @example @@ -213,6 +214,17 @@ function httpPost( * }); * // Returns: Tracer with CloudTraceSink * + * // With screenshot processor for PII redaction + * const redactPII = (screenshot: string): string => { + * // Your custom redaction logic + * return redactedScreenshot; + * }; + * const tracer = await createTracer({ + * apiKey: "sk_pro_xyz", + * screenshotProcessor: redactPII + * }); + * // Screenshots will be processed before upload + * * // Pro tier user with local-only tracing * const tracer = await createTracer({ apiKey: "sk_pro_xyz", runId: "demo", uploadTrace: false }); * // Returns: Tracer with JsonlTraceSink (local-only) @@ -237,6 +249,7 @@ export async function createTracer(options: { agentType?: string; llmModel?: string; startUrl?: string; + screenshotProcessor?: (screenshot: string) => string; }): Promise { const runId = options.runId || randomUUID(); const apiUrl = options.apiUrl || SENTIENCE_API_URL; @@ -292,7 +305,8 @@ export async function createTracer(options: { // PRODUCTION FIX: Pass runId for persistent cache naming return new Tracer( runId, - new CloudTraceSink(uploadUrl, runId, options.apiKey, apiUrl, options.logger) + new CloudTraceSink(uploadUrl, runId, options.apiKey, apiUrl, options.logger), + options.screenshotProcessor ); } else if (response.status === 403) { console.log('⚠️ [Sentience] Cloud tracing requires Pro tier'); @@ -324,7 +338,7 @@ export async function createTracer(options: { const localPath = path.join(tracesDir, `${runId}.jsonl`); console.log(`💾 [Sentience] Local tracing: ${localPath}`); - return new Tracer(runId, new JsonlTraceSink(localPath)); + return new Tracer(runId, new JsonlTraceSink(localPath), options.screenshotProcessor); } /** diff --git a/src/tracing/tracer.ts b/src/tracing/tracer.ts index 02f39cc7..786c1ea4 100644 --- a/src/tracing/tracer.ts +++ b/src/tracing/tracer.ts @@ -14,6 +14,7 @@ export class Tracer { private runId: string; private sink: TraceSink; private seq: number; + private screenshotProcessor?: (screenshot: string) => string; // Stats tracking private totalSteps: number = 0; @@ -30,11 +31,32 @@ export class Tracer { * Create a new Tracer * @param runId - Unique run identifier (UUID) * @param sink - TraceSink implementation (e.g., JsonlTraceSink) + * @param screenshotProcessor - Optional function to process screenshots before emission. + * Takes base64 string, returns processed base64 string. + * Useful for PII redaction or custom image processing. + * + * @example + * // Basic usage + * const sink = new JsonlTraceSink('trace.jsonl'); + * const tracer = new Tracer('run-123', sink); + * + * @example + * // With screenshot processor for PII redaction + * const redactPII = (screenshot: string): string => { + * // Your custom redaction logic + * return redactedScreenshot; + * }; + * const tracer = new Tracer('run-123', sink, redactPII); */ - constructor(runId: string, sink: TraceSink) { + constructor( + runId: string, + sink: TraceSink, + screenshotProcessor?: (screenshot: string) => string + ) { this.runId = runId; this.sink = sink; this.seq = 0; + this.screenshotProcessor = screenshotProcessor; } /** @@ -47,6 +69,12 @@ export class Tracer { this.seq += 1; this.totalEvents += 1; + // Apply screenshot processor if configured and screenshot is present + if (this.screenshotProcessor && data.screenshot_base64) { + data = { ...data }; // Don't modify the original object + data.screenshot_base64 = this.screenshotProcessor(data.screenshot_base64); + } + // Generate timestamps const tsMs = Date.now(); const ts = new Date(tsMs).toISOString(); From d06de372002dcd4899bbd800c98d28e4bc2f85c4 Mon Sep 17 00:00:00 2001 From: rcholic Date: Sat, 3 Jan 2026 18:44:37 -0800 Subject: [PATCH 2/2] fix test --- src/tracing/tracer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tracing/tracer.ts b/src/tracing/tracer.ts index 786c1ea4..e6da064a 100644 --- a/src/tracing/tracer.ts +++ b/src/tracing/tracer.ts @@ -71,8 +71,8 @@ export class Tracer { // Apply screenshot processor if configured and screenshot is present if (this.screenshotProcessor && data.screenshot_base64) { - data = { ...data }; // Don't modify the original object - data.screenshot_base64 = this.screenshotProcessor(data.screenshot_base64); + const processedScreenshot = this.screenshotProcessor(data.screenshot_base64); + data = { ...data, screenshot_base64: processedScreenshot }; // Don't modify the original object } // Generate timestamps