Skip to content

Commit ca1cf6a

Browse files
author
Sentience Dev
committed
Merge pull request #98 from SentienceAPI/pii
hook for redacting PII for screenshots
2 parents 32d8a3e + 323e70a commit ca1cf6a

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

src/tracing/tracer-factory.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ function httpPost(
197197
* @param options.agentType - Type of agent running (e.g., "SentienceAgent", "CustomAgent")
198198
* @param options.llmModel - LLM model used (e.g., "gpt-4-turbo", "claude-3-5-sonnet")
199199
* @param options.startUrl - Starting URL of the agent run (e.g., "https://amazon.com")
200+
* @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.
200201
* @returns Tracer configured with appropriate sink
201202
*
202203
* @example
@@ -213,6 +214,17 @@ function httpPost(
213214
* });
214215
* // Returns: Tracer with CloudTraceSink
215216
*
217+
* // With screenshot processor for PII redaction
218+
* const redactPII = (screenshot: string): string => {
219+
* // Your custom redaction logic
220+
* return redactedScreenshot;
221+
* };
222+
* const tracer = await createTracer({
223+
* apiKey: "sk_pro_xyz",
224+
* screenshotProcessor: redactPII
225+
* });
226+
* // Screenshots will be processed before upload
227+
*
216228
* // Pro tier user with local-only tracing
217229
* const tracer = await createTracer({ apiKey: "sk_pro_xyz", runId: "demo", uploadTrace: false });
218230
* // Returns: Tracer with JsonlTraceSink (local-only)
@@ -237,6 +249,7 @@ export async function createTracer(options: {
237249
agentType?: string;
238250
llmModel?: string;
239251
startUrl?: string;
252+
screenshotProcessor?: (screenshot: string) => string;
240253
}): Promise<Tracer> {
241254
const runId = options.runId || randomUUID();
242255
const apiUrl = options.apiUrl || SENTIENCE_API_URL;
@@ -292,7 +305,8 @@ export async function createTracer(options: {
292305
// PRODUCTION FIX: Pass runId for persistent cache naming
293306
return new Tracer(
294307
runId,
295-
new CloudTraceSink(uploadUrl, runId, options.apiKey, apiUrl, options.logger)
308+
new CloudTraceSink(uploadUrl, runId, options.apiKey, apiUrl, options.logger),
309+
options.screenshotProcessor
296310
);
297311
} else if (response.status === 403) {
298312
console.log('⚠️ [Sentience] Cloud tracing requires Pro tier');
@@ -324,7 +338,7 @@ export async function createTracer(options: {
324338
const localPath = path.join(tracesDir, `${runId}.jsonl`);
325339
console.log(`💾 [Sentience] Local tracing: ${localPath}`);
326340

327-
return new Tracer(runId, new JsonlTraceSink(localPath));
341+
return new Tracer(runId, new JsonlTraceSink(localPath), options.screenshotProcessor);
328342
}
329343

330344
/**

src/tracing/tracer.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class Tracer {
1414
private runId: string;
1515
private sink: TraceSink;
1616
private seq: number;
17+
private screenshotProcessor?: (screenshot: string) => string;
1718

1819
// Stats tracking
1920
private totalSteps: number = 0;
@@ -30,11 +31,32 @@ export class Tracer {
3031
* Create a new Tracer
3132
* @param runId - Unique run identifier (UUID)
3233
* @param sink - TraceSink implementation (e.g., JsonlTraceSink)
34+
* @param screenshotProcessor - Optional function to process screenshots before emission.
35+
* Takes base64 string, returns processed base64 string.
36+
* Useful for PII redaction or custom image processing.
37+
*
38+
* @example
39+
* // Basic usage
40+
* const sink = new JsonlTraceSink('trace.jsonl');
41+
* const tracer = new Tracer('run-123', sink);
42+
*
43+
* @example
44+
* // With screenshot processor for PII redaction
45+
* const redactPII = (screenshot: string): string => {
46+
* // Your custom redaction logic
47+
* return redactedScreenshot;
48+
* };
49+
* const tracer = new Tracer('run-123', sink, redactPII);
3350
*/
34-
constructor(runId: string, sink: TraceSink) {
51+
constructor(
52+
runId: string,
53+
sink: TraceSink,
54+
screenshotProcessor?: (screenshot: string) => string
55+
) {
3556
this.runId = runId;
3657
this.sink = sink;
3758
this.seq = 0;
59+
this.screenshotProcessor = screenshotProcessor;
3860
}
3961

4062
/**
@@ -47,6 +69,12 @@ export class Tracer {
4769
this.seq += 1;
4870
this.totalEvents += 1;
4971

72+
// Apply screenshot processor if configured and screenshot is present
73+
if (this.screenshotProcessor && data.screenshot_base64) {
74+
const processedScreenshot = this.screenshotProcessor(data.screenshot_base64);
75+
data = { ...data, screenshot_base64: processedScreenshot }; // Don't modify the original object
76+
}
77+
5078
// Generate timestamps
5179
const tsMs = Date.now();
5280
const ts = new Date(tsMs).toISOString();

0 commit comments

Comments
 (0)