Skip to content

Commit fbf08f2

Browse files
committed
upload screenshots along with traces
1 parent 679246d commit fbf08f2

4 files changed

Lines changed: 342 additions & 3 deletions

File tree

src/agent.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export class SentienceAgent {
8888
private stepCount: number;
8989
private history: HistoryEntry[];
9090
private tokenUsage: TokenStats;
91+
private screenshotSequence: number;
9192

9293
/**
9394
* Initialize Sentience Agent
@@ -117,6 +118,9 @@ export class SentienceAgent {
117118
totalTokens: 0,
118119
byAction: []
119120
};
121+
122+
// Screenshot sequence counter
123+
this.screenshotSequence = 0;
120124
}
121125

122126
/**
@@ -171,6 +175,23 @@ export class SentienceAgent {
171175
throw new Error(`Snapshot failed: ${snap.error}`);
172176
}
173177

178+
// Store screenshot if captured
179+
if (snap.screenshot && this.tracer) {
180+
this.screenshotSequence += 1;
181+
const seq = this.screenshotSequence;
182+
183+
// Store screenshot in CloudTraceSink if available
184+
const sink = (this.tracer as any).sink;
185+
if (sink && typeof sink.storeScreenshot === 'function') {
186+
sink.storeScreenshot(
187+
seq,
188+
snap.screenshot,
189+
snap.screenshot_format || 'jpeg',
190+
stepId
191+
);
192+
}
193+
}
194+
174195
// Apply element filtering based on goal
175196
const filteredElements = this.filterElements(snap, goal);
176197

src/tracing/cloud-sink.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as https from 'https';
1818
import * as http from 'http';
1919
import { URL } from 'url';
2020
import { TraceSink } from './sink';
21+
import { ScreenshotMetadata } from '../types';
2122

2223
/**
2324
* Optional logger interface for SDK users
@@ -75,10 +76,19 @@ export class CloudTraceSink extends TraceSink {
7576
private apiUrl: string;
7677
private logger?: SentienceLogger;
7778

78-
// File size tracking (NEW)
79+
// File size tracking
7980
private traceFileSizeBytes: number = 0;
8081
private screenshotTotalSizeBytes: number = 0;
8182

83+
// Screenshot storage directory
84+
private screenshotDir: string;
85+
86+
// Screenshot metadata tracking (sequence -> ScreenshotMetadata)
87+
private screenshotMetadata: Map<number, ScreenshotMetadata> = new Map();
88+
89+
// Upload success flag
90+
private uploadSuccessful: boolean = false;
91+
8292
/**
8393
* Create a new CloudTraceSink
8494
*
@@ -107,6 +117,12 @@ export class CloudTraceSink extends TraceSink {
107117
const cacheDir = getPersistentCacheDir();
108118
this.tempFilePath = path.join(cacheDir, `${this.runId}.jsonl`);
109119

120+
// Screenshot storage directory
121+
this.screenshotDir = path.join(cacheDir, `${this.runId}_screenshots`);
122+
if (!fs.existsSync(this.screenshotDir)) {
123+
fs.mkdirSync(this.screenshotDir, { recursive: true });
124+
}
125+
110126
try {
111127
// Open file in append mode
112128
this.writeStream = fs.createWriteStream(this.tempFilePath, {
@@ -282,17 +298,25 @@ export class CloudTraceSink extends TraceSink {
282298
const statusCode = await this._uploadToCloud(compressedData);
283299

284300
if (statusCode === 200) {
301+
this.uploadSuccessful = true;
285302
console.log('✅ [Sentience] Trace uploaded successfully');
286303

304+
// Upload screenshots after trace upload succeeds
305+
if (this.screenshotMetadata.size > 0) {
306+
console.log(`📸 [Sentience] Uploading ${this.screenshotMetadata.size} screenshots...`);
307+
await this._uploadScreenshots();
308+
}
309+
287310
// Upload trace index file
288311
await this._uploadIndex();
289312

290313
// Call /v1/traces/complete to report file sizes
291314
await this._completeTrace();
292315

293-
// 4. Delete temp file on success
294-
await fsPromises.unlink(this.tempFilePath);
316+
// 4. Delete files on success
317+
await this._cleanupFiles();
295318
} else {
319+
this.uploadSuccessful = false;
296320
console.error(`❌ [Sentience] Upload failed: HTTP ${statusCode}`);
297321
console.error(` Local trace preserved at: ${this.tempFilePath}`);
298322
}
@@ -323,6 +347,7 @@ export class CloudTraceSink extends TraceSink {
323347
stats: {
324348
trace_file_size_bytes: this.traceFileSizeBytes,
325349
screenshot_total_size_bytes: this.screenshotTotalSizeBytes,
350+
screenshot_count: this.screenshotMetadata.size,
326351
},
327352
});
328353

src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ export interface Snapshot {
5050
requires_license?: boolean;
5151
}
5252

53+
/**
54+
* Metadata for a stored screenshot.
55+
* Used by CloudTraceSink to track screenshots before upload.
56+
*/
57+
export interface ScreenshotMetadata {
58+
sequence: number;
59+
format: "png" | "jpeg";
60+
sizeBytes: number;
61+
stepId: string | null;
62+
filepath: string;
63+
}
64+
5365
export interface ActionResult {
5466
success: boolean;
5567
duration_ms: number;

0 commit comments

Comments
 (0)