Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/tracing/tracer-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -237,6 +249,7 @@ export async function createTracer(options: {
agentType?: string;
llmModel?: string;
startUrl?: string;
screenshotProcessor?: (screenshot: string) => string;
}): Promise<Tracer> {
const runId = options.runId || randomUUID();
const apiUrl = options.apiUrl || SENTIENCE_API_URL;
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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);
}

/**
Expand Down
30 changes: 29 additions & 1 deletion src/tracing/tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

/**
Expand All @@ -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) {
const processedScreenshot = this.screenshotProcessor(data.screenshot_base64);
data = { ...data, screenshot_base64: processedScreenshot }; // Don't modify the original object
}

// Generate timestamps
const tsMs = Date.now();
const ts = new Date(tsMs).toISOString();
Expand Down
Loading