agi 0.4.0 → 0.5.1
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 +58 -514
- package/bin/agi +3 -0
- package/dist/index.d.mts +1 -1426
- package/dist/index.mjs +363 -1693
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -41
- package/LICENSE +0 -21
- package/dist/index.d.ts +0 -1427
- package/dist/index.js +0 -1742
- package/dist/index.js.map +0 -1
package/dist/index.js
DELETED
|
@@ -1,1742 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var eventsourceParser = require('eventsource-parser');
|
|
4
|
-
var child_process = require('child_process');
|
|
5
|
-
var events = require('events');
|
|
6
|
-
var readline = require('readline');
|
|
7
|
-
var fs = require('fs');
|
|
8
|
-
var path = require('path');
|
|
9
|
-
var url = require('url');
|
|
10
|
-
var os = require('os');
|
|
11
|
-
var module$1 = require('module');
|
|
12
|
-
|
|
13
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
14
|
-
// src/http.ts
|
|
15
|
-
|
|
16
|
-
// src/errors.ts
|
|
17
|
-
var AGIError = class _AGIError extends Error {
|
|
18
|
-
constructor(message, statusCode, response) {
|
|
19
|
-
super(message);
|
|
20
|
-
this.statusCode = statusCode;
|
|
21
|
-
this.response = response;
|
|
22
|
-
this.name = "AGIError";
|
|
23
|
-
Object.setPrototypeOf(this, _AGIError.prototype);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
var AuthenticationError = class _AuthenticationError extends AGIError {
|
|
27
|
-
constructor(message, response) {
|
|
28
|
-
super(message, 401, response);
|
|
29
|
-
this.name = "AuthenticationError";
|
|
30
|
-
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
var NotFoundError = class _NotFoundError extends AGIError {
|
|
34
|
-
constructor(message, response) {
|
|
35
|
-
super(message, 404, response);
|
|
36
|
-
this.name = "NotFoundError";
|
|
37
|
-
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
var RateLimitError = class _RateLimitError extends AGIError {
|
|
41
|
-
constructor(message, response) {
|
|
42
|
-
super(message, 429, response);
|
|
43
|
-
this.name = "RateLimitError";
|
|
44
|
-
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
var AgentExecutionError = class _AgentExecutionError extends AGIError {
|
|
48
|
-
constructor(message, response) {
|
|
49
|
-
super(message, void 0, response);
|
|
50
|
-
this.name = "AgentExecutionError";
|
|
51
|
-
Object.setPrototypeOf(this, _AgentExecutionError.prototype);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
var ValidationError = class _ValidationError extends AGIError {
|
|
55
|
-
constructor(message, response) {
|
|
56
|
-
super(message, 422, response);
|
|
57
|
-
this.name = "ValidationError";
|
|
58
|
-
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
var PermissionError = class _PermissionError extends AGIError {
|
|
62
|
-
constructor(message, response) {
|
|
63
|
-
super(message, 403, response);
|
|
64
|
-
this.name = "PermissionError";
|
|
65
|
-
Object.setPrototypeOf(this, _PermissionError.prototype);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
var APIError = class _APIError extends AGIError {
|
|
69
|
-
constructor(message, statusCode, response) {
|
|
70
|
-
super(message, statusCode, response);
|
|
71
|
-
this.name = "APIError";
|
|
72
|
-
Object.setPrototypeOf(this, _APIError.prototype);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// src/http.ts
|
|
77
|
-
var HTTPClient = class {
|
|
78
|
-
apiKey;
|
|
79
|
-
baseUrl;
|
|
80
|
-
timeout;
|
|
81
|
-
maxRetries;
|
|
82
|
-
constructor(options) {
|
|
83
|
-
this.apiKey = options.apiKey;
|
|
84
|
-
this.baseUrl = options.baseUrl ?? "https://api.agi.tech";
|
|
85
|
-
this.timeout = options.timeout ?? 6e4;
|
|
86
|
-
this.maxRetries = options.maxRetries ?? 3;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Make an HTTP request with retries and error handling
|
|
90
|
-
*/
|
|
91
|
-
async request(method, path, options) {
|
|
92
|
-
const url = this.buildUrl(path, options?.query);
|
|
93
|
-
const headers = this.buildHeaders(options?.headers);
|
|
94
|
-
let lastError;
|
|
95
|
-
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
96
|
-
try {
|
|
97
|
-
const controller = new AbortController();
|
|
98
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
99
|
-
const response = await fetch(url, {
|
|
100
|
-
method,
|
|
101
|
-
headers,
|
|
102
|
-
body: options?.json ? JSON.stringify(options.json) : void 0,
|
|
103
|
-
signal: controller.signal
|
|
104
|
-
});
|
|
105
|
-
clearTimeout(timeoutId);
|
|
106
|
-
if (!response.ok) {
|
|
107
|
-
await this.handleErrorResponse(response);
|
|
108
|
-
}
|
|
109
|
-
const data = await response.json();
|
|
110
|
-
return data;
|
|
111
|
-
} catch (error) {
|
|
112
|
-
lastError = error;
|
|
113
|
-
if (error instanceof AGIError && error.statusCode && error.statusCode < 500) {
|
|
114
|
-
if (error.statusCode !== 429) {
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (attempt === this.maxRetries) {
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
await this.sleep(Math.pow(2, attempt) * 1e3);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
throw lastError || new AGIError("Request failed after retries");
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Make an HTTP request to an absolute URL with retries and error handling
|
|
128
|
-
*/
|
|
129
|
-
async requestUrl(method, url, options) {
|
|
130
|
-
const headers = this.buildHeaders(options?.headers);
|
|
131
|
-
let lastError;
|
|
132
|
-
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
133
|
-
try {
|
|
134
|
-
const controller = new AbortController();
|
|
135
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
136
|
-
const response = await fetch(url, {
|
|
137
|
-
method,
|
|
138
|
-
headers,
|
|
139
|
-
body: options?.json ? JSON.stringify(options.json) : void 0,
|
|
140
|
-
signal: controller.signal
|
|
141
|
-
});
|
|
142
|
-
clearTimeout(timeoutId);
|
|
143
|
-
if (!response.ok) {
|
|
144
|
-
await this.handleErrorResponse(response);
|
|
145
|
-
}
|
|
146
|
-
const data = await response.json();
|
|
147
|
-
return data;
|
|
148
|
-
} catch (error) {
|
|
149
|
-
lastError = error;
|
|
150
|
-
if (error instanceof AGIError && error.statusCode && error.statusCode < 500) {
|
|
151
|
-
if (error.statusCode !== 429) {
|
|
152
|
-
throw error;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (attempt === this.maxRetries) {
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
await this.sleep(Math.pow(2, attempt) * 1e3);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
throw lastError || new AGIError("Request failed after retries");
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Stream Server-Sent Events from an endpoint
|
|
165
|
-
*/
|
|
166
|
-
async *streamEvents(path, query) {
|
|
167
|
-
const url = this.buildUrl(path, query);
|
|
168
|
-
const headers = this.buildHeaders();
|
|
169
|
-
const controller = new AbortController();
|
|
170
|
-
const response = await fetch(url, {
|
|
171
|
-
method: "GET",
|
|
172
|
-
headers: {
|
|
173
|
-
...headers,
|
|
174
|
-
Accept: "text/event-stream"
|
|
175
|
-
},
|
|
176
|
-
signal: controller.signal
|
|
177
|
-
});
|
|
178
|
-
if (!response.ok) {
|
|
179
|
-
await this.handleErrorResponse(response);
|
|
180
|
-
}
|
|
181
|
-
if (!response.body) {
|
|
182
|
-
throw new AGIError("Response body is null");
|
|
183
|
-
}
|
|
184
|
-
const reader = response.body.getReader();
|
|
185
|
-
const decoder = new TextDecoder();
|
|
186
|
-
let buffer = "";
|
|
187
|
-
const parser = eventsourceParser.createParser((event) => {
|
|
188
|
-
if (event.type === "event") {
|
|
189
|
-
try {
|
|
190
|
-
const data = JSON.parse(event.data);
|
|
191
|
-
this.pendingEvents.push({
|
|
192
|
-
id: event.id,
|
|
193
|
-
event: event.event,
|
|
194
|
-
data
|
|
195
|
-
});
|
|
196
|
-
} catch {
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
const pendingEvents = [];
|
|
201
|
-
this.pendingEvents = pendingEvents;
|
|
202
|
-
try {
|
|
203
|
-
while (true) {
|
|
204
|
-
const { done, value } = await reader.read();
|
|
205
|
-
if (done) {
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
buffer += decoder.decode(value, { stream: true });
|
|
209
|
-
parser.feed(buffer);
|
|
210
|
-
buffer = "";
|
|
211
|
-
while (pendingEvents.length > 0) {
|
|
212
|
-
const event = pendingEvents.shift();
|
|
213
|
-
if (event) {
|
|
214
|
-
yield event;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} finally {
|
|
219
|
-
controller.abort();
|
|
220
|
-
reader.releaseLock();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
pendingEvents = [];
|
|
224
|
-
buildUrl(path, query) {
|
|
225
|
-
const url = new URL(path, this.baseUrl);
|
|
226
|
-
if (query) {
|
|
227
|
-
Object.entries(query).forEach(([key, value]) => {
|
|
228
|
-
url.searchParams.append(key, value);
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
return url.toString();
|
|
232
|
-
}
|
|
233
|
-
buildHeaders(additional) {
|
|
234
|
-
return {
|
|
235
|
-
"Content-Type": "application/json",
|
|
236
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
237
|
-
"User-Agent": "agi-sdk-node/1.0.0",
|
|
238
|
-
...additional
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
async handleErrorResponse(response) {
|
|
242
|
-
let errorData;
|
|
243
|
-
const text = await response.text();
|
|
244
|
-
try {
|
|
245
|
-
errorData = JSON.parse(text);
|
|
246
|
-
} catch {
|
|
247
|
-
errorData = text;
|
|
248
|
-
}
|
|
249
|
-
const errorMessage = typeof errorData === "object" && errorData.message ? errorData.message : typeof errorData === "string" ? errorData : `HTTP ${response.status}: ${response.statusText}`;
|
|
250
|
-
switch (response.status) {
|
|
251
|
-
case 401:
|
|
252
|
-
throw new AuthenticationError(`Authentication failed: ${errorMessage}`, errorData);
|
|
253
|
-
case 403:
|
|
254
|
-
throw new PermissionError(`Permission denied: ${errorMessage}`, errorData);
|
|
255
|
-
case 404:
|
|
256
|
-
throw new NotFoundError(`Resource not found: ${errorMessage}`, errorData);
|
|
257
|
-
case 422:
|
|
258
|
-
throw new ValidationError(`Validation error: ${errorMessage}`, errorData);
|
|
259
|
-
case 429:
|
|
260
|
-
throw new RateLimitError(`Rate limit exceeded: ${errorMessage}`, errorData);
|
|
261
|
-
default:
|
|
262
|
-
if (response.status >= 500) {
|
|
263
|
-
throw new APIError(
|
|
264
|
-
`Server error (${response.status}): ${errorMessage}`,
|
|
265
|
-
response.status,
|
|
266
|
-
errorData
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
throw new AGIError(
|
|
270
|
-
`API error (${response.status}): ${errorMessage}`,
|
|
271
|
-
response.status,
|
|
272
|
-
errorData
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
sleep(ms) {
|
|
277
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
// src/types/screenshot.ts
|
|
282
|
-
var Screenshot = class _Screenshot {
|
|
283
|
-
constructor(data, format, timestamp, width, height, url, title) {
|
|
284
|
-
this.data = data;
|
|
285
|
-
this.format = format;
|
|
286
|
-
this.timestamp = timestamp;
|
|
287
|
-
this.width = width;
|
|
288
|
-
this.height = height;
|
|
289
|
-
this.url = url;
|
|
290
|
-
this.title = title;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Save screenshot to file
|
|
294
|
-
*
|
|
295
|
-
* @param path - File path to save to (e.g., "screenshot.png")
|
|
296
|
-
*
|
|
297
|
-
* @example
|
|
298
|
-
* ```typescript
|
|
299
|
-
* const screenshot = await session.screenshot();
|
|
300
|
-
* await screenshot.save("amazon.png");
|
|
301
|
-
* ```
|
|
302
|
-
*/
|
|
303
|
-
async save(path) {
|
|
304
|
-
const fs = await import('fs/promises');
|
|
305
|
-
await fs.writeFile(path, this.data);
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Create Screenshot from base64 data URL
|
|
309
|
-
*
|
|
310
|
-
* @param base64Data - Base64-encoded data URL (e.g., "data:image/jpeg;base64,...")
|
|
311
|
-
* @param url - Current page URL
|
|
312
|
-
* @param title - Current page title
|
|
313
|
-
* @param timestamp - Screenshot timestamp (defaults to now)
|
|
314
|
-
* @returns Screenshot instance with decoded image data
|
|
315
|
-
*/
|
|
316
|
-
static fromBase64(base64Data, url, title, timestamp) {
|
|
317
|
-
let header;
|
|
318
|
-
let encoded;
|
|
319
|
-
if (base64Data.includes(",")) {
|
|
320
|
-
[header, encoded] = base64Data.split(",", 2);
|
|
321
|
-
} else {
|
|
322
|
-
encoded = base64Data;
|
|
323
|
-
header = "data:image/png;base64";
|
|
324
|
-
}
|
|
325
|
-
const imageData = Buffer.from(encoded, "base64");
|
|
326
|
-
const format = header.toLowerCase().includes("jpeg") || header.toLowerCase().includes("jpg") ? "jpg" : "png";
|
|
327
|
-
const { width, height } = _Screenshot.getImageDimensions(imageData, format);
|
|
328
|
-
return new _Screenshot(imageData, format, timestamp || /* @__PURE__ */ new Date(), width, height, url, title);
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Extract width and height from image data
|
|
332
|
-
*
|
|
333
|
-
* @param data - Raw image bytes
|
|
334
|
-
* @param format - Image format (png, jpg)
|
|
335
|
-
* @returns Tuple of (width, height)
|
|
336
|
-
*/
|
|
337
|
-
static getImageDimensions(data, format) {
|
|
338
|
-
try {
|
|
339
|
-
if (format === "png" && data.length >= 24) {
|
|
340
|
-
const width = data.readUInt32BE(16);
|
|
341
|
-
const height = data.readUInt32BE(20);
|
|
342
|
-
return { width, height };
|
|
343
|
-
} else if (format === "jpg") {
|
|
344
|
-
for (let i = 0; i < data.length - 9; i++) {
|
|
345
|
-
if (data[i] === 255 && data[i + 1] === 192) {
|
|
346
|
-
const height = data.readUInt16BE(i + 5);
|
|
347
|
-
const width = data.readUInt16BE(i + 7);
|
|
348
|
-
return { width, height };
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
} catch (error) {
|
|
353
|
-
}
|
|
354
|
-
return { width: 0, height: 0 };
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
// src/context/session-context.ts
|
|
359
|
-
var SessionContext = class {
|
|
360
|
-
constructor(client, agentName = "agi-0", createOptions) {
|
|
361
|
-
this.client = client;
|
|
362
|
-
this.agentName = agentName;
|
|
363
|
-
this.createOptions = createOptions;
|
|
364
|
-
}
|
|
365
|
-
sessionId;
|
|
366
|
-
vncUrl;
|
|
367
|
-
agentUrl;
|
|
368
|
-
/**
|
|
369
|
-
* Automatic cleanup via explicit resource management
|
|
370
|
-
*/
|
|
371
|
-
async [Symbol.asyncDispose]() {
|
|
372
|
-
if (this.sessionId) {
|
|
373
|
-
try {
|
|
374
|
-
await this.client.sessions.delete(this.sessionId);
|
|
375
|
-
} catch (error) {
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Ensure session is created
|
|
381
|
-
*/
|
|
382
|
-
async ensureSession() {
|
|
383
|
-
if (this.sessionId) return;
|
|
384
|
-
const response = await this.client.sessions.create(this.agentName, this.createOptions);
|
|
385
|
-
this.sessionId = response.sessionId;
|
|
386
|
-
this.vncUrl = response.vncUrl;
|
|
387
|
-
this.agentUrl = response.agentUrl;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Run a task and wait for completion using HTTP polling
|
|
391
|
-
*
|
|
392
|
-
* This method uses HTTP polling instead of SSE streaming for better reliability
|
|
393
|
-
* with long-running tasks and network instability.
|
|
394
|
-
*
|
|
395
|
-
* @param task - Natural language task description
|
|
396
|
-
* @param options - Task execution options
|
|
397
|
-
* @returns TaskResult with data and execution metadata
|
|
398
|
-
*
|
|
399
|
-
* @example
|
|
400
|
-
* ```typescript
|
|
401
|
-
* const result = await session.runTask(
|
|
402
|
-
* 'Find cheapest iPhone 15 Pro',
|
|
403
|
-
* { timeout: 300000, pollInterval: 2000 } // 5 min timeout, 2s polling
|
|
404
|
-
* );
|
|
405
|
-
* console.log(result.data);
|
|
406
|
-
* console.log(`Took ${result.metadata.duration}s, ${result.metadata.steps} steps`);
|
|
407
|
-
* ```
|
|
408
|
-
*/
|
|
409
|
-
async runTask(task, options) {
|
|
410
|
-
await this.ensureSession();
|
|
411
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
412
|
-
const timeout = options?.timeout ?? 6e5;
|
|
413
|
-
const pollInterval = options?.pollInterval ?? 3e3;
|
|
414
|
-
await this.client.sessions.sendMessage(this.sessionId, task, {
|
|
415
|
-
startUrl: options?.startUrl
|
|
416
|
-
});
|
|
417
|
-
const startTime = Date.now();
|
|
418
|
-
while (true) {
|
|
419
|
-
const elapsed = Date.now() - startTime;
|
|
420
|
-
if (elapsed > timeout) {
|
|
421
|
-
throw new AgentExecutionError(
|
|
422
|
-
`Task exceeded timeout of ${timeout}ms (elapsed: ${elapsed}ms)`
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
const statusResponse = await this.client.sessions.getStatus(this.sessionId);
|
|
426
|
-
if (statusResponse.status === "finished" || statusResponse.status === "waiting_for_input") {
|
|
427
|
-
const messagesResponse = await this.client.sessions.getMessages(this.sessionId);
|
|
428
|
-
const messages = messagesResponse.messages;
|
|
429
|
-
const doneMsg = messages.find((msg) => msg.type === "DONE" || msg.type === "QUESTION");
|
|
430
|
-
if (!doneMsg) {
|
|
431
|
-
throw new AgentExecutionError(
|
|
432
|
-
`Task status '${statusResponse.status}' but no DONE/QUESTION message found`
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
const content = doneMsg.content;
|
|
436
|
-
const data = typeof content === "object" && content !== null ? content : { content: content ?? {} };
|
|
437
|
-
const duration = (Date.now() - startTime) / 1e3;
|
|
438
|
-
const steps = messages.filter(
|
|
439
|
-
(msg) => ["THOUGHT", "QUESTION", "DONE"].includes(msg.type)
|
|
440
|
-
).length;
|
|
441
|
-
const metadata = {
|
|
442
|
-
taskId: doneMsg.id,
|
|
443
|
-
sessionId: this.sessionId,
|
|
444
|
-
duration,
|
|
445
|
-
cost: 0,
|
|
446
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
447
|
-
steps,
|
|
448
|
-
success: true
|
|
449
|
-
};
|
|
450
|
-
return { data, metadata };
|
|
451
|
-
}
|
|
452
|
-
if (statusResponse.status === "error") {
|
|
453
|
-
const messagesResponse = await this.client.sessions.getMessages(this.sessionId);
|
|
454
|
-
const errorMsg = messagesResponse.messages.find((msg) => msg.type === "ERROR");
|
|
455
|
-
const errorDetails = errorMsg ? typeof errorMsg.content === "string" ? errorMsg.content : JSON.stringify(errorMsg.content) : "Unknown error";
|
|
456
|
-
throw new AgentExecutionError(`Task failed: ${errorDetails}`);
|
|
457
|
-
}
|
|
458
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Send a message to the agent
|
|
463
|
-
*
|
|
464
|
-
* @param message - Message content
|
|
465
|
-
* @param options - Message options
|
|
466
|
-
* @returns SuccessResponse confirming message was sent
|
|
467
|
-
*
|
|
468
|
-
* @example
|
|
469
|
-
* ```typescript
|
|
470
|
-
* await session.sendMessage('Find flights from SFO to JFK under $450');
|
|
471
|
-
* ```
|
|
472
|
-
*/
|
|
473
|
-
async sendMessage(message, options) {
|
|
474
|
-
await this.ensureSession();
|
|
475
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
476
|
-
return this.client.sessions.sendMessage(this.sessionId, message, options);
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Get current execution status
|
|
480
|
-
*
|
|
481
|
-
* @returns ExecuteStatusResponse with status
|
|
482
|
-
*
|
|
483
|
-
* @example
|
|
484
|
-
* ```typescript
|
|
485
|
-
* const status = await session.getStatus();
|
|
486
|
-
* console.log(status.status);
|
|
487
|
-
* ```
|
|
488
|
-
*/
|
|
489
|
-
async getStatus() {
|
|
490
|
-
await this.ensureSession();
|
|
491
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
492
|
-
return this.client.sessions.getStatus(this.sessionId);
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Get messages from the session
|
|
496
|
-
*
|
|
497
|
-
* @param afterId - Return messages with ID > afterId (for polling)
|
|
498
|
-
* @param sanitize - Filter out system messages, prompts, and images
|
|
499
|
-
* @returns MessagesResponse with messages list and status
|
|
500
|
-
*
|
|
501
|
-
* @example
|
|
502
|
-
* ```typescript
|
|
503
|
-
* const messages = await session.getMessages(0);
|
|
504
|
-
* for (const msg of messages.messages) {
|
|
505
|
-
* console.log(`[${msg.type}] ${msg.content}`);
|
|
506
|
-
* }
|
|
507
|
-
* ```
|
|
508
|
-
*/
|
|
509
|
-
async getMessages(afterId, sanitize = true) {
|
|
510
|
-
await this.ensureSession();
|
|
511
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
512
|
-
return this.client.sessions.getMessages(this.sessionId, afterId, sanitize);
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Stream real-time events from the session via Server-Sent Events
|
|
516
|
-
*
|
|
517
|
-
* @param options - Stream options
|
|
518
|
-
* @yields SSEEvent objects
|
|
519
|
-
*
|
|
520
|
-
* @example
|
|
521
|
-
* ```typescript
|
|
522
|
-
* for await (const event of session.streamEvents()) {
|
|
523
|
-
* if (event.event === 'thought') {
|
|
524
|
-
* console.log('Agent:', event.data);
|
|
525
|
-
* }
|
|
526
|
-
* if (event.event === 'done') {
|
|
527
|
-
* console.log('Result:', event.data);
|
|
528
|
-
* break;
|
|
529
|
-
* }
|
|
530
|
-
* }
|
|
531
|
-
* ```
|
|
532
|
-
*/
|
|
533
|
-
async *streamEvents(options) {
|
|
534
|
-
await this.ensureSession();
|
|
535
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
536
|
-
yield* this.client.sessions.streamEvents(this.sessionId, options);
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Pause task execution
|
|
540
|
-
*
|
|
541
|
-
* @returns SuccessResponse confirming pause
|
|
542
|
-
*
|
|
543
|
-
* @example
|
|
544
|
-
* ```typescript
|
|
545
|
-
* await session.pause();
|
|
546
|
-
* ```
|
|
547
|
-
*/
|
|
548
|
-
async pause() {
|
|
549
|
-
await this.ensureSession();
|
|
550
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
551
|
-
return this.client.sessions.pause(this.sessionId);
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Resume paused task
|
|
555
|
-
*
|
|
556
|
-
* @returns SuccessResponse confirming resume
|
|
557
|
-
*
|
|
558
|
-
* @example
|
|
559
|
-
* ```typescript
|
|
560
|
-
* await session.resume();
|
|
561
|
-
* ```
|
|
562
|
-
*/
|
|
563
|
-
async resume() {
|
|
564
|
-
await this.ensureSession();
|
|
565
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
566
|
-
return this.client.sessions.resume(this.sessionId);
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Cancel task execution
|
|
570
|
-
*
|
|
571
|
-
* @returns SuccessResponse confirming cancellation
|
|
572
|
-
*
|
|
573
|
-
* @example
|
|
574
|
-
* ```typescript
|
|
575
|
-
* await session.cancel();
|
|
576
|
-
* ```
|
|
577
|
-
*/
|
|
578
|
-
async cancel() {
|
|
579
|
-
await this.ensureSession();
|
|
580
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
581
|
-
return this.client.sessions.cancel(this.sessionId);
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Navigate browser to URL
|
|
585
|
-
*
|
|
586
|
-
* @param url - URL to navigate to
|
|
587
|
-
* @returns NavigateResponse with current URL
|
|
588
|
-
*
|
|
589
|
-
* @example
|
|
590
|
-
* ```typescript
|
|
591
|
-
* await session.navigate('https://amazon.com');
|
|
592
|
-
* ```
|
|
593
|
-
*/
|
|
594
|
-
async navigate(url) {
|
|
595
|
-
await this.ensureSession();
|
|
596
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
597
|
-
return this.client.sessions.navigate(this.sessionId, url);
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Get browser screenshot
|
|
601
|
-
*
|
|
602
|
-
* @returns Screenshot with decoded image data and save() method
|
|
603
|
-
*
|
|
604
|
-
* @example
|
|
605
|
-
* ```typescript
|
|
606
|
-
* const screenshot = await session.screenshot();
|
|
607
|
-
* await screenshot.save('page.png');
|
|
608
|
-
* console.log(`Size: ${screenshot.width}x${screenshot.height}`);
|
|
609
|
-
* ```
|
|
610
|
-
*/
|
|
611
|
-
async screenshot() {
|
|
612
|
-
await this.ensureSession();
|
|
613
|
-
if (!this.sessionId) throw new Error("Session not created");
|
|
614
|
-
const response = await this.client.sessions.screenshot(this.sessionId);
|
|
615
|
-
return Screenshot.fromBase64(response.screenshot, response.url, response.title);
|
|
616
|
-
}
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
// src/utils.ts
|
|
620
|
-
function normalizeSessionResponse(data) {
|
|
621
|
-
return {
|
|
622
|
-
sessionId: data.session_id ?? data.sessionId,
|
|
623
|
-
vncUrl: data.vnc_url ?? data.vncUrl,
|
|
624
|
-
agentUrl: data.agent_url ?? data.agentUrl,
|
|
625
|
-
agentName: data.agent_name ?? data.agentName,
|
|
626
|
-
status: data.status,
|
|
627
|
-
createdAt: data.created_at ?? data.createdAt,
|
|
628
|
-
environmentId: data.environment_id ?? data.environmentId,
|
|
629
|
-
goal: data.goal,
|
|
630
|
-
agentSessionType: data.agent_session_type ?? data.agentSessionType
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// src/resources/sessions.ts
|
|
635
|
-
var SessionsResource = class {
|
|
636
|
-
constructor(http) {
|
|
637
|
-
this.http = http;
|
|
638
|
-
}
|
|
639
|
-
// ===== SESSION MANAGEMENT =====
|
|
640
|
-
/**
|
|
641
|
-
* Create a new agent session
|
|
642
|
-
*
|
|
643
|
-
* @param agentName - Agent model to use (e.g., "agi-0", "agi-2-claude")
|
|
644
|
-
* @param options - Session creation options
|
|
645
|
-
* @returns SessionResponse with sessionId, vncUrl, agentUrl, status, etc.
|
|
646
|
-
*
|
|
647
|
-
* @example
|
|
648
|
-
* ```typescript
|
|
649
|
-
* // Standard browser session
|
|
650
|
-
* const session = await client.sessions.create('agi-0', {
|
|
651
|
-
* webhookUrl: 'https://yourapp.com/webhook',
|
|
652
|
-
* maxSteps: 200
|
|
653
|
-
* });
|
|
654
|
-
*
|
|
655
|
-
* // Desktop session (client-managed)
|
|
656
|
-
* const session = await client.sessions.create('agi-2-claude', {
|
|
657
|
-
* agentSessionType: 'desktop',
|
|
658
|
-
* goal: 'Open calculator and compute 2+2'
|
|
659
|
-
* });
|
|
660
|
-
* console.log(session.agentUrl); // Use with client.desktop.step()
|
|
661
|
-
* ```
|
|
662
|
-
*/
|
|
663
|
-
async create(agentName = "agi-0", options) {
|
|
664
|
-
const payload = {
|
|
665
|
-
agent_name: agentName,
|
|
666
|
-
max_steps: options?.maxSteps ?? 100
|
|
667
|
-
};
|
|
668
|
-
if (options?.webhookUrl) payload.webhook_url = options.webhookUrl;
|
|
669
|
-
if (options?.goal) payload.goal = options.goal;
|
|
670
|
-
if (options?.restoreFromEnvironmentId) {
|
|
671
|
-
payload.restore_from_environment_id = options.restoreFromEnvironmentId;
|
|
672
|
-
}
|
|
673
|
-
if (options?.agentSessionType) {
|
|
674
|
-
payload.agent_session_type = options.agentSessionType;
|
|
675
|
-
}
|
|
676
|
-
if (options?.cdpUrl) payload.cdp_url = options.cdpUrl;
|
|
677
|
-
const response = await this.http.request("POST", "/v1/sessions", {
|
|
678
|
-
json: payload
|
|
679
|
-
});
|
|
680
|
-
return normalizeSessionResponse(response);
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* List all sessions for the authenticated user
|
|
684
|
-
*
|
|
685
|
-
* @returns Array of SessionResponse objects
|
|
686
|
-
*
|
|
687
|
-
* @example
|
|
688
|
-
* ```typescript
|
|
689
|
-
* const sessions = await client.sessions.list();
|
|
690
|
-
* for (const session of sessions) {
|
|
691
|
-
* console.log(`${session.sessionId}: ${session.status}`);
|
|
692
|
-
* }
|
|
693
|
-
* ```
|
|
694
|
-
*/
|
|
695
|
-
async list() {
|
|
696
|
-
const responses = await this.http.request(
|
|
697
|
-
"GET",
|
|
698
|
-
"/v1/sessions"
|
|
699
|
-
);
|
|
700
|
-
return responses.map(normalizeSessionResponse);
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Get details for a specific session
|
|
704
|
-
*
|
|
705
|
-
* @param sessionId - Session UUID
|
|
706
|
-
* @returns SessionResponse with session details
|
|
707
|
-
*
|
|
708
|
-
* @example
|
|
709
|
-
* ```typescript
|
|
710
|
-
* const session = await client.sessions.get('session-uuid');
|
|
711
|
-
* console.log(session.status);
|
|
712
|
-
* ```
|
|
713
|
-
*/
|
|
714
|
-
async get(sessionId) {
|
|
715
|
-
const response = await this.http.request(
|
|
716
|
-
"GET",
|
|
717
|
-
`/v1/sessions/${sessionId}`
|
|
718
|
-
);
|
|
719
|
-
return normalizeSessionResponse(response);
|
|
720
|
-
}
|
|
721
|
-
/**
|
|
722
|
-
* Delete a session and cleanup its resources
|
|
723
|
-
*
|
|
724
|
-
* @param sessionId - Session UUID
|
|
725
|
-
* @param saveSnapshotMode - Snapshot mode: "none", "memory", or "filesystem"
|
|
726
|
-
* @returns DeleteResponse confirming deletion
|
|
727
|
-
*
|
|
728
|
-
* @example
|
|
729
|
-
* ```typescript
|
|
730
|
-
* await client.sessions.delete('session-uuid', 'filesystem');
|
|
731
|
-
* ```
|
|
732
|
-
*/
|
|
733
|
-
async delete(sessionId, saveSnapshotMode = "none") {
|
|
734
|
-
return this.http.request("DELETE", `/v1/sessions/${sessionId}`, {
|
|
735
|
-
query: { save_snapshot_mode: saveSnapshotMode }
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Delete all sessions for the authenticated user
|
|
740
|
-
*
|
|
741
|
-
* @returns DeleteResponse with count of deleted sessions
|
|
742
|
-
*
|
|
743
|
-
* @example
|
|
744
|
-
* ```typescript
|
|
745
|
-
* const result = await client.sessions.deleteAll();
|
|
746
|
-
* console.log(result.message);
|
|
747
|
-
* ```
|
|
748
|
-
*/
|
|
749
|
-
async deleteAll() {
|
|
750
|
-
return this.http.request("DELETE", "/v1/sessions");
|
|
751
|
-
}
|
|
752
|
-
// ===== AGENT INTERACTION =====
|
|
753
|
-
/**
|
|
754
|
-
* Send a message to the agent to start a task or respond to questions
|
|
755
|
-
*
|
|
756
|
-
* @param sessionId - Session UUID
|
|
757
|
-
* @param message - Message content (task instruction or response)
|
|
758
|
-
* @param options - Message options
|
|
759
|
-
* @returns SuccessResponse confirming message was sent
|
|
760
|
-
*
|
|
761
|
-
* @example
|
|
762
|
-
* ```typescript
|
|
763
|
-
* await client.sessions.sendMessage(
|
|
764
|
-
* 'session-uuid',
|
|
765
|
-
* 'Find flights from SFO to JFK under $450'
|
|
766
|
-
* );
|
|
767
|
-
* ```
|
|
768
|
-
*/
|
|
769
|
-
async sendMessage(sessionId, message, options) {
|
|
770
|
-
return this.http.request("POST", `/v1/sessions/${sessionId}/message`, {
|
|
771
|
-
json: {
|
|
772
|
-
message,
|
|
773
|
-
start_url: options?.startUrl,
|
|
774
|
-
config_updates: options?.configUpdates
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Get the current execution status of a session
|
|
780
|
-
*
|
|
781
|
-
* @param sessionId - Session UUID
|
|
782
|
-
* @returns ExecuteStatusResponse with status
|
|
783
|
-
*
|
|
784
|
-
* @example
|
|
785
|
-
* ```typescript
|
|
786
|
-
* const status = await client.sessions.getStatus('session-uuid');
|
|
787
|
-
* if (status.status === 'finished') {
|
|
788
|
-
* console.log('Task completed!');
|
|
789
|
-
* }
|
|
790
|
-
* ```
|
|
791
|
-
*/
|
|
792
|
-
async getStatus(sessionId) {
|
|
793
|
-
return this.http.request("GET", `/v1/sessions/${sessionId}/status`);
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Poll for messages and updates from the agent
|
|
797
|
-
*
|
|
798
|
-
* @param sessionId - Session UUID
|
|
799
|
-
* @param afterId - Return messages with ID > afterId (for polling)
|
|
800
|
-
* @param sanitize - Filter out system messages, prompts, and images
|
|
801
|
-
* @returns MessagesResponse with messages list and status
|
|
802
|
-
*
|
|
803
|
-
* @example
|
|
804
|
-
* ```typescript
|
|
805
|
-
* const messages = await client.sessions.getMessages('session-uuid', 0);
|
|
806
|
-
* for (const msg of messages.messages) {
|
|
807
|
-
* console.log(`[${msg.type}] ${msg.content}`);
|
|
808
|
-
* }
|
|
809
|
-
* ```
|
|
810
|
-
*/
|
|
811
|
-
async getMessages(sessionId, afterId = 0, sanitize = true) {
|
|
812
|
-
const response = await this.http.request(
|
|
813
|
-
"GET",
|
|
814
|
-
`/v1/sessions/${sessionId}/messages`,
|
|
815
|
-
{
|
|
816
|
-
query: {
|
|
817
|
-
after_id: String(afterId),
|
|
818
|
-
sanitize: String(sanitize)
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
);
|
|
822
|
-
return {
|
|
823
|
-
messages: response.messages || [],
|
|
824
|
-
status: response.status,
|
|
825
|
-
hasAgent: response.has_agent ?? response.hasAgent ?? false
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* Stream real-time events from the session via Server-Sent Events
|
|
830
|
-
*
|
|
831
|
-
* @param sessionId - Session UUID
|
|
832
|
-
* @param options - Stream options
|
|
833
|
-
* @yields SSEEvent objects
|
|
834
|
-
*
|
|
835
|
-
* @example
|
|
836
|
-
* ```typescript
|
|
837
|
-
* for await (const event of client.sessions.streamEvents('session-uuid')) {
|
|
838
|
-
* if (event.event === 'thought') {
|
|
839
|
-
* console.log('Agent:', event.data);
|
|
840
|
-
* }
|
|
841
|
-
* if (event.event === 'done') {
|
|
842
|
-
* console.log('Result:', event.data);
|
|
843
|
-
* break;
|
|
844
|
-
* }
|
|
845
|
-
* }
|
|
846
|
-
* ```
|
|
847
|
-
*/
|
|
848
|
-
async *streamEvents(sessionId, options) {
|
|
849
|
-
const query = {
|
|
850
|
-
sanitize: String(options?.sanitize ?? true),
|
|
851
|
-
include_history: String(options?.includeHistory ?? true)
|
|
852
|
-
};
|
|
853
|
-
if (options?.eventTypes) {
|
|
854
|
-
query.event_types = options.eventTypes.join(",");
|
|
855
|
-
}
|
|
856
|
-
yield* this.http.streamEvents(`/v1/sessions/${sessionId}/events`, query);
|
|
857
|
-
}
|
|
858
|
-
// ===== SESSION CONTROL =====
|
|
859
|
-
/**
|
|
860
|
-
* Temporarily pause task execution
|
|
861
|
-
*
|
|
862
|
-
* @param sessionId - Session UUID
|
|
863
|
-
* @returns SuccessResponse confirming pause
|
|
864
|
-
*
|
|
865
|
-
* @example
|
|
866
|
-
* ```typescript
|
|
867
|
-
* await client.sessions.pause('session-uuid');
|
|
868
|
-
* ```
|
|
869
|
-
*/
|
|
870
|
-
async pause(sessionId) {
|
|
871
|
-
return this.http.request("POST", `/v1/sessions/${sessionId}/pause`);
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Resume a paused task
|
|
875
|
-
*
|
|
876
|
-
* @param sessionId - Session UUID
|
|
877
|
-
* @returns SuccessResponse confirming resume
|
|
878
|
-
*
|
|
879
|
-
* @example
|
|
880
|
-
* ```typescript
|
|
881
|
-
* await client.sessions.resume('session-uuid');
|
|
882
|
-
* ```
|
|
883
|
-
*/
|
|
884
|
-
async resume(sessionId) {
|
|
885
|
-
return this.http.request("POST", `/v1/sessions/${sessionId}/resume`);
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Cancel task execution
|
|
889
|
-
*
|
|
890
|
-
* @param sessionId - Session UUID
|
|
891
|
-
* @returns SuccessResponse confirming cancellation
|
|
892
|
-
*
|
|
893
|
-
* @example
|
|
894
|
-
* ```typescript
|
|
895
|
-
* await client.sessions.cancel('session-uuid');
|
|
896
|
-
* ```
|
|
897
|
-
*/
|
|
898
|
-
async cancel(sessionId) {
|
|
899
|
-
return this.http.request("POST", `/v1/sessions/${sessionId}/cancel`);
|
|
900
|
-
}
|
|
901
|
-
// ===== BROWSER CONTROL =====
|
|
902
|
-
/**
|
|
903
|
-
* Navigate the browser to a specific URL
|
|
904
|
-
*
|
|
905
|
-
* @param sessionId - Session UUID
|
|
906
|
-
* @param url - URL to navigate to
|
|
907
|
-
* @returns NavigateResponse with current URL
|
|
908
|
-
*
|
|
909
|
-
* @example
|
|
910
|
-
* ```typescript
|
|
911
|
-
* await client.sessions.navigate('session-uuid', 'https://amazon.com');
|
|
912
|
-
* ```
|
|
913
|
-
*/
|
|
914
|
-
async navigate(sessionId, url) {
|
|
915
|
-
const response = await this.http.request(
|
|
916
|
-
"POST",
|
|
917
|
-
`/v1/sessions/${sessionId}/navigate`,
|
|
918
|
-
{
|
|
919
|
-
json: { url }
|
|
920
|
-
}
|
|
921
|
-
);
|
|
922
|
-
return {
|
|
923
|
-
currentUrl: response.current_url ?? response.currentUrl
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
/**
|
|
927
|
-
* Get a screenshot of the browser
|
|
928
|
-
*
|
|
929
|
-
* @param sessionId - Session UUID
|
|
930
|
-
* @returns ScreenshotResponse with base64-encoded image, URL, and title
|
|
931
|
-
*
|
|
932
|
-
* @example
|
|
933
|
-
* ```typescript
|
|
934
|
-
* const screenshot = await client.sessions.screenshot('session-uuid');
|
|
935
|
-
* console.log(screenshot.url);
|
|
936
|
-
* ```
|
|
937
|
-
*/
|
|
938
|
-
async screenshot(sessionId) {
|
|
939
|
-
return this.http.request("GET", `/v1/sessions/${sessionId}/screenshot`);
|
|
940
|
-
}
|
|
941
|
-
// ===== CLIENT-DRIVEN SESSION CONTROL =====
|
|
942
|
-
/**
|
|
943
|
-
* Execute a single step for client-driven sessions (desktop mode).
|
|
944
|
-
*
|
|
945
|
-
* In desktop mode (agentSessionType="desktop"), the client manages the
|
|
946
|
-
* execution loop. This method sends a screenshot to the agent and receives
|
|
947
|
-
* actions to execute locally.
|
|
948
|
-
*
|
|
949
|
-
* @param agentUrl - Agent service URL from session.agentUrl
|
|
950
|
-
* @param sessionId - Session ID (required for routing in shared sandbox)
|
|
951
|
-
* @param screenshot - Base64-encoded screenshot (full resolution, JPEG or PNG)
|
|
952
|
-
* @param message - Optional user message (goal on first call, or follow-up instruction)
|
|
953
|
-
* @returns StepDesktopResponse with actions, thinking, finished, askUser, and step
|
|
954
|
-
*
|
|
955
|
-
* @example
|
|
956
|
-
* ```typescript
|
|
957
|
-
* // Create a desktop session
|
|
958
|
-
* const session = await client.sessions.create('agi-2-claude', {
|
|
959
|
-
* agentSessionType: 'desktop',
|
|
960
|
-
* goal: 'Open calculator and compute 2+2'
|
|
961
|
-
* });
|
|
962
|
-
*
|
|
963
|
-
* // Client-managed loop
|
|
964
|
-
* let finished = false;
|
|
965
|
-
* while (!finished) {
|
|
966
|
-
* const screenshot = captureScreenshot(); // Client captures
|
|
967
|
-
* const result = await client.sessions.step(
|
|
968
|
-
* session.agentUrl!,
|
|
969
|
-
* session.sessionId,
|
|
970
|
-
* screenshot
|
|
971
|
-
* );
|
|
972
|
-
* executeActions(result.actions); // Client executes
|
|
973
|
-
* finished = result.finished;
|
|
974
|
-
* if (result.askUser) {
|
|
975
|
-
* const answer = await promptUser(result.askUser);
|
|
976
|
-
* // Send answer in next step
|
|
977
|
-
* }
|
|
978
|
-
* }
|
|
979
|
-
* ```
|
|
980
|
-
*/
|
|
981
|
-
async step(agentUrl, sessionId, screenshot, message) {
|
|
982
|
-
const url = `${agentUrl.replace(/\/$/, "")}/step_desktop`;
|
|
983
|
-
const payload = { screenshot, session_id: sessionId };
|
|
984
|
-
if (message !== void 0) {
|
|
985
|
-
payload.message = message;
|
|
986
|
-
}
|
|
987
|
-
const response = await this.http.requestUrl("POST", url, {
|
|
988
|
-
json: payload
|
|
989
|
-
});
|
|
990
|
-
return {
|
|
991
|
-
actions: response.actions || [],
|
|
992
|
-
thinking: response.thinking,
|
|
993
|
-
finished: response.finished ?? false,
|
|
994
|
-
askUser: response.ask_user ?? response.askUser,
|
|
995
|
-
step: response.step ?? 0
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
// ===== MODELS =====
|
|
999
|
-
/**
|
|
1000
|
-
* List available agent models.
|
|
1001
|
-
*
|
|
1002
|
-
* @param filter - Optional filter: "cdp" for browser agents, "desktop" for
|
|
1003
|
-
* desktop agents
|
|
1004
|
-
* @returns ModelsResponse with list of available model names
|
|
1005
|
-
*
|
|
1006
|
-
* @example
|
|
1007
|
-
* ```typescript
|
|
1008
|
-
* // List all models
|
|
1009
|
-
* const models = await client.sessions.listModels();
|
|
1010
|
-
* console.log(models.models);
|
|
1011
|
-
*
|
|
1012
|
-
* // List only desktop-compatible models
|
|
1013
|
-
* const desktopModels = await client.sessions.listModels('desktop');
|
|
1014
|
-
* console.log(desktopModels.models);
|
|
1015
|
-
* // ['agi-2-claude', 'agi-2-qwen']
|
|
1016
|
-
* ```
|
|
1017
|
-
*/
|
|
1018
|
-
async listModels(filter) {
|
|
1019
|
-
const query = {};
|
|
1020
|
-
if (filter) {
|
|
1021
|
-
query.filter = filter;
|
|
1022
|
-
}
|
|
1023
|
-
return this.http.request("GET", "/v1/models", { query });
|
|
1024
|
-
}
|
|
1025
|
-
};
|
|
1026
|
-
|
|
1027
|
-
// src/client.ts
|
|
1028
|
-
var AGIClient = class {
|
|
1029
|
-
http;
|
|
1030
|
-
/** Sessions resource for low-level API access */
|
|
1031
|
-
sessions;
|
|
1032
|
-
/**
|
|
1033
|
-
* Create a new AGI client
|
|
1034
|
-
*
|
|
1035
|
-
* @param options - Client configuration options
|
|
1036
|
-
*
|
|
1037
|
-
* @example
|
|
1038
|
-
* ```typescript
|
|
1039
|
-
* // With explicit API key
|
|
1040
|
-
* const client = new AGIClient({ apiKey: 'your_api_key' });
|
|
1041
|
-
*
|
|
1042
|
-
* // With custom base URL
|
|
1043
|
-
* const client = new AGIClient({
|
|
1044
|
-
* apiKey: 'your_api_key',
|
|
1045
|
-
* baseUrl: 'https://custom-api.example.com',
|
|
1046
|
-
* timeout: 120000,
|
|
1047
|
-
* });
|
|
1048
|
-
* ```
|
|
1049
|
-
*/
|
|
1050
|
-
constructor(options) {
|
|
1051
|
-
if (!options.apiKey) {
|
|
1052
|
-
throw new Error(
|
|
1053
|
-
"api_key is required. Either pass it as a parameter or set the AGI_API_KEY environment variable."
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
this.http = new HTTPClient(options);
|
|
1057
|
-
this.sessions = new SessionsResource(this.http);
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Create a session context manager for easy session lifecycle management (recommended)
|
|
1061
|
-
*
|
|
1062
|
-
* This is the recommended way to use the SDK. The context manager automatically
|
|
1063
|
-
* creates and deletes the session using `await using` syntax.
|
|
1064
|
-
*
|
|
1065
|
-
* @param agentName - Agent model to use (e.g., "agi-0", "agi-0-fast", "agi-1")
|
|
1066
|
-
* @param options - Session creation options
|
|
1067
|
-
* @returns SessionContext manager
|
|
1068
|
-
*
|
|
1069
|
-
* @example
|
|
1070
|
-
* ```typescript
|
|
1071
|
-
* // Simple usage
|
|
1072
|
-
* await using session = client.session('agi-0');
|
|
1073
|
-
* const result = await session.runTask('Find flights SFO→JFK under $450');
|
|
1074
|
-
* console.log(result.data);
|
|
1075
|
-
* // Session automatically deleted
|
|
1076
|
-
*
|
|
1077
|
-
* // With options
|
|
1078
|
-
* await using session = client.session('agi-0', {
|
|
1079
|
-
* webhookUrl: 'https://yourapp.com/webhook',
|
|
1080
|
-
* maxSteps: 200
|
|
1081
|
-
* });
|
|
1082
|
-
* const result = await session.runTask('Research company XYZ');
|
|
1083
|
-
* ```
|
|
1084
|
-
*/
|
|
1085
|
-
session(agentName = "agi-0", options) {
|
|
1086
|
-
return new SessionContext(this, agentName, options);
|
|
1087
|
-
}
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
// src/loop.ts
|
|
1091
|
-
var AgentLoop = class {
|
|
1092
|
-
client;
|
|
1093
|
-
agentUrl;
|
|
1094
|
-
sessionId;
|
|
1095
|
-
captureScreenshot;
|
|
1096
|
-
executeActions;
|
|
1097
|
-
onThinking;
|
|
1098
|
-
onAskUser;
|
|
1099
|
-
onStep;
|
|
1100
|
-
stepDelay;
|
|
1101
|
-
_state = "idle";
|
|
1102
|
-
_lastResult = null;
|
|
1103
|
-
_currentStep = 0;
|
|
1104
|
-
// Pause control using Promise-based approach
|
|
1105
|
-
pauseResolve = null;
|
|
1106
|
-
pausePromise = null;
|
|
1107
|
-
constructor(options) {
|
|
1108
|
-
this.client = options.client;
|
|
1109
|
-
this.agentUrl = options.agentUrl;
|
|
1110
|
-
this.sessionId = options.sessionId;
|
|
1111
|
-
this.captureScreenshot = options.captureScreenshot;
|
|
1112
|
-
this.executeActions = options.executeActions;
|
|
1113
|
-
this.onThinking = options.onThinking;
|
|
1114
|
-
this.onAskUser = options.onAskUser;
|
|
1115
|
-
this.onStep = options.onStep;
|
|
1116
|
-
this.stepDelay = options.stepDelay ?? 0;
|
|
1117
|
-
}
|
|
1118
|
-
/** Current state of the loop. */
|
|
1119
|
-
get state() {
|
|
1120
|
-
return this._state;
|
|
1121
|
-
}
|
|
1122
|
-
/** Current step number. */
|
|
1123
|
-
get currentStep() {
|
|
1124
|
-
return this._currentStep;
|
|
1125
|
-
}
|
|
1126
|
-
/** Last step result, if any. */
|
|
1127
|
-
get lastResult() {
|
|
1128
|
-
return this._lastResult;
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* Start the execution loop.
|
|
1132
|
-
*
|
|
1133
|
-
* Runs the loop until the task is finished, stopped, or an unhandled
|
|
1134
|
-
* ask_user question is encountered.
|
|
1135
|
-
*
|
|
1136
|
-
* @param message - Optional initial message (goal or instruction).
|
|
1137
|
-
* Usually not needed if goal was set during session creation.
|
|
1138
|
-
* @returns The final StepDesktopResponse
|
|
1139
|
-
* @throws Error if loop is already running
|
|
1140
|
-
*/
|
|
1141
|
-
async start(message) {
|
|
1142
|
-
if (this._state === "running") {
|
|
1143
|
-
throw new Error("Loop is already running");
|
|
1144
|
-
}
|
|
1145
|
-
this._state = "running";
|
|
1146
|
-
let currentMessage = message;
|
|
1147
|
-
let result = null;
|
|
1148
|
-
try {
|
|
1149
|
-
while (true) {
|
|
1150
|
-
if (this.pausePromise) {
|
|
1151
|
-
await this.pausePromise;
|
|
1152
|
-
}
|
|
1153
|
-
const currentState = this._state;
|
|
1154
|
-
if (currentState === "paused") {
|
|
1155
|
-
continue;
|
|
1156
|
-
}
|
|
1157
|
-
if (currentState !== "running") {
|
|
1158
|
-
break;
|
|
1159
|
-
}
|
|
1160
|
-
const screenshot = await this.captureScreenshot();
|
|
1161
|
-
result = await this.client.sessions.step(
|
|
1162
|
-
this.agentUrl,
|
|
1163
|
-
this.sessionId,
|
|
1164
|
-
screenshot,
|
|
1165
|
-
currentMessage
|
|
1166
|
-
);
|
|
1167
|
-
currentMessage = void 0;
|
|
1168
|
-
this._lastResult = result;
|
|
1169
|
-
this._currentStep = result.step;
|
|
1170
|
-
if (result.thinking && this.onThinking) {
|
|
1171
|
-
this.onThinking(result.thinking);
|
|
1172
|
-
}
|
|
1173
|
-
if (this.onStep) {
|
|
1174
|
-
this.onStep(result.step, result);
|
|
1175
|
-
}
|
|
1176
|
-
if (result.askUser) {
|
|
1177
|
-
if (this.onAskUser) {
|
|
1178
|
-
const answer = await this.onAskUser(result.askUser);
|
|
1179
|
-
currentMessage = answer;
|
|
1180
|
-
} else {
|
|
1181
|
-
this._state = "stopped";
|
|
1182
|
-
return result;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
if (result.actions.length > 0) {
|
|
1186
|
-
await this.executeActions(result.actions);
|
|
1187
|
-
}
|
|
1188
|
-
if (result.finished) {
|
|
1189
|
-
this._state = "finished";
|
|
1190
|
-
return result;
|
|
1191
|
-
}
|
|
1192
|
-
if (this.stepDelay > 0) {
|
|
1193
|
-
await new Promise((resolve) => setTimeout(resolve, this.stepDelay));
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
} catch (error) {
|
|
1197
|
-
this._state = "stopped";
|
|
1198
|
-
throw error;
|
|
1199
|
-
}
|
|
1200
|
-
if (result === null) {
|
|
1201
|
-
result = {
|
|
1202
|
-
actions: [],
|
|
1203
|
-
thinking: void 0,
|
|
1204
|
-
finished: true,
|
|
1205
|
-
askUser: void 0,
|
|
1206
|
-
step: this._currentStep
|
|
1207
|
-
};
|
|
1208
|
-
}
|
|
1209
|
-
return result;
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* Pause the execution loop.
|
|
1213
|
-
*
|
|
1214
|
-
* The loop will complete the current step before pausing.
|
|
1215
|
-
* Call resume() to continue.
|
|
1216
|
-
*/
|
|
1217
|
-
pause() {
|
|
1218
|
-
if (this._state !== "running") {
|
|
1219
|
-
return;
|
|
1220
|
-
}
|
|
1221
|
-
this._state = "paused";
|
|
1222
|
-
this.pausePromise = new Promise((resolve) => {
|
|
1223
|
-
this.pauseResolve = resolve;
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Resume a paused loop.
|
|
1228
|
-
*/
|
|
1229
|
-
resume() {
|
|
1230
|
-
if (this._state !== "paused") {
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
this._state = "running";
|
|
1234
|
-
if (this.pauseResolve) {
|
|
1235
|
-
this.pauseResolve();
|
|
1236
|
-
this.pauseResolve = null;
|
|
1237
|
-
this.pausePromise = null;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
/**
|
|
1241
|
-
* Stop the execution loop.
|
|
1242
|
-
*
|
|
1243
|
-
* The loop will complete the current step before stopping.
|
|
1244
|
-
*/
|
|
1245
|
-
stop() {
|
|
1246
|
-
this._state = "stopped";
|
|
1247
|
-
if (this.pauseResolve) {
|
|
1248
|
-
this.pauseResolve();
|
|
1249
|
-
this.pauseResolve = null;
|
|
1250
|
-
this.pausePromise = null;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
/** Check if the loop is currently running. */
|
|
1254
|
-
isRunning() {
|
|
1255
|
-
return this._state === "running";
|
|
1256
|
-
}
|
|
1257
|
-
/** Check if the loop is currently paused. */
|
|
1258
|
-
isPaused() {
|
|
1259
|
-
return this._state === "paused";
|
|
1260
|
-
}
|
|
1261
|
-
/** Check if the loop has finished successfully. */
|
|
1262
|
-
isFinished() {
|
|
1263
|
-
return this._state === "finished";
|
|
1264
|
-
}
|
|
1265
|
-
};
|
|
1266
|
-
var __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
1267
|
-
var __dirname$1 = path.dirname(__filename$1);
|
|
1268
|
-
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
1269
|
-
function getPlatformId() {
|
|
1270
|
-
const os$1 = os.platform();
|
|
1271
|
-
const cpu = os.arch();
|
|
1272
|
-
if (os$1 === "darwin") {
|
|
1273
|
-
return cpu === "arm64" ? "darwin-arm64" : "darwin-x64";
|
|
1274
|
-
} else if (os$1 === "linux") {
|
|
1275
|
-
return "linux-x64";
|
|
1276
|
-
} else if (os$1 === "win32") {
|
|
1277
|
-
return "win32-x64";
|
|
1278
|
-
}
|
|
1279
|
-
throw new Error(`Unsupported platform: ${os$1}-${cpu}`);
|
|
1280
|
-
}
|
|
1281
|
-
function getBinaryFilename(platformId) {
|
|
1282
|
-
const id = platformId ?? getPlatformId();
|
|
1283
|
-
if (id === "win32-x64") {
|
|
1284
|
-
return "agi-driver.exe";
|
|
1285
|
-
}
|
|
1286
|
-
return "agi-driver";
|
|
1287
|
-
}
|
|
1288
|
-
function getSearchPaths(platformId) {
|
|
1289
|
-
const filename = getBinaryFilename(platformId);
|
|
1290
|
-
const paths = [];
|
|
1291
|
-
const packageName = `@agi/agi-${platformId}`;
|
|
1292
|
-
try {
|
|
1293
|
-
const packagePath = require2.resolve(`${packageName}/package.json`);
|
|
1294
|
-
const packageDir = path.dirname(packagePath);
|
|
1295
|
-
paths.push(path.join(packageDir, filename));
|
|
1296
|
-
} catch {
|
|
1297
|
-
}
|
|
1298
|
-
paths.push(path.join(__dirname$1, "..", "..", "bin", filename));
|
|
1299
|
-
paths.push(path.join(__dirname$1, "..", "..", "..", "bin", filename));
|
|
1300
|
-
const envPath = process.env.PATH || "";
|
|
1301
|
-
for (const dir of envPath.split(path.delimiter)) {
|
|
1302
|
-
if (dir) {
|
|
1303
|
-
paths.push(path.join(dir, filename));
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
return paths;
|
|
1307
|
-
}
|
|
1308
|
-
function getPythonFallback() {
|
|
1309
|
-
const driverPath = process.env.AGI_DRIVER_PATH;
|
|
1310
|
-
if (driverPath && fs.existsSync(path.join(driverPath, "__main__.py"))) {
|
|
1311
|
-
return {
|
|
1312
|
-
command: process.env.PYTHON_PATH || "python",
|
|
1313
|
-
args: ["-m", "agi_driver"]
|
|
1314
|
-
};
|
|
1315
|
-
}
|
|
1316
|
-
return null;
|
|
1317
|
-
}
|
|
1318
|
-
function findBinaryPath() {
|
|
1319
|
-
const platformId = getPlatformId();
|
|
1320
|
-
const searchPaths = getSearchPaths(platformId);
|
|
1321
|
-
for (const path of searchPaths) {
|
|
1322
|
-
if (fs.existsSync(path)) {
|
|
1323
|
-
return path;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
throw new Error(
|
|
1327
|
-
`Could not find agi-driver binary for ${platformId}. Searched: ${searchPaths.join(", ")}. Install the optional dependency @agi/agi-${platformId} or ensure agi-driver is in PATH.`
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1330
|
-
function isBinaryAvailable() {
|
|
1331
|
-
try {
|
|
1332
|
-
findBinaryPath();
|
|
1333
|
-
return true;
|
|
1334
|
-
} catch {
|
|
1335
|
-
return false;
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
// src/driver/protocol.ts
|
|
1340
|
-
function parseEvent(line) {
|
|
1341
|
-
const data = JSON.parse(line);
|
|
1342
|
-
return data;
|
|
1343
|
-
}
|
|
1344
|
-
function serializeCommand(command) {
|
|
1345
|
-
return JSON.stringify(command);
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
// src/driver/driver.ts
|
|
1349
|
-
var AgentDriver = class extends events.EventEmitter {
|
|
1350
|
-
binaryPath;
|
|
1351
|
-
pythonFallback;
|
|
1352
|
-
model;
|
|
1353
|
-
platform;
|
|
1354
|
-
mode;
|
|
1355
|
-
env;
|
|
1356
|
-
process = null;
|
|
1357
|
-
readline = null;
|
|
1358
|
-
state = "idle";
|
|
1359
|
-
step = 0;
|
|
1360
|
-
sessionId = "";
|
|
1361
|
-
screenWidth = 0;
|
|
1362
|
-
screenHeight = 0;
|
|
1363
|
-
resolveStart = null;
|
|
1364
|
-
rejectStart = null;
|
|
1365
|
-
// Pending callbacks for user interaction
|
|
1366
|
-
pendingConfirm = null;
|
|
1367
|
-
pendingAnswer = null;
|
|
1368
|
-
constructor(options = {}) {
|
|
1369
|
-
super();
|
|
1370
|
-
let binaryPath = null;
|
|
1371
|
-
try {
|
|
1372
|
-
binaryPath = options.binaryPath ?? findBinaryPath();
|
|
1373
|
-
} catch {
|
|
1374
|
-
}
|
|
1375
|
-
this.binaryPath = binaryPath;
|
|
1376
|
-
this.pythonFallback = binaryPath ? null : getPythonFallback();
|
|
1377
|
-
if (!this.binaryPath && !this.pythonFallback) {
|
|
1378
|
-
throw new Error(
|
|
1379
|
-
"Could not find agi-driver binary and Python fallback is not available. Set AGI_DRIVER_PATH to the agi_driver source directory for development."
|
|
1380
|
-
);
|
|
1381
|
-
}
|
|
1382
|
-
this.model = options.model ?? "claude-sonnet";
|
|
1383
|
-
this.platform = options.platform ?? "desktop";
|
|
1384
|
-
this.mode = options.mode ?? "";
|
|
1385
|
-
this.env = options.env ?? {};
|
|
1386
|
-
}
|
|
1387
|
-
/**
|
|
1388
|
-
* Get the current state of the driver.
|
|
1389
|
-
*/
|
|
1390
|
-
get currentState() {
|
|
1391
|
-
return this.state;
|
|
1392
|
-
}
|
|
1393
|
-
/**
|
|
1394
|
-
* Get the current step number.
|
|
1395
|
-
*/
|
|
1396
|
-
get currentStep() {
|
|
1397
|
-
return this.step;
|
|
1398
|
-
}
|
|
1399
|
-
/**
|
|
1400
|
-
* Check if the driver is running.
|
|
1401
|
-
*/
|
|
1402
|
-
get isRunning() {
|
|
1403
|
-
return this.state === "running";
|
|
1404
|
-
}
|
|
1405
|
-
/**
|
|
1406
|
-
* Check if the driver is waiting for user input.
|
|
1407
|
-
*/
|
|
1408
|
-
get isWaiting() {
|
|
1409
|
-
return this.state === "waiting_confirmation" || this.state === "waiting_answer";
|
|
1410
|
-
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Start the agent with a goal.
|
|
1413
|
-
*
|
|
1414
|
-
* @param goal - The task for the agent to accomplish
|
|
1415
|
-
* @param screenshot - Initial screenshot (base64-encoded). Not needed in local mode.
|
|
1416
|
-
* @param screenWidth - Screen width in pixels. Not needed in local mode.
|
|
1417
|
-
* @param screenHeight - Screen height in pixels. Not needed in local mode.
|
|
1418
|
-
* @param mode - Override the mode set in DriverOptions.
|
|
1419
|
-
* @returns Promise that resolves when the agent finishes
|
|
1420
|
-
*/
|
|
1421
|
-
async start(goal, screenshot = "", screenWidth = 0, screenHeight = 0, mode) {
|
|
1422
|
-
if (this.process) {
|
|
1423
|
-
throw new Error("Driver is already running");
|
|
1424
|
-
}
|
|
1425
|
-
this.sessionId = `session_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1426
|
-
this.screenWidth = screenWidth;
|
|
1427
|
-
this.screenHeight = screenHeight;
|
|
1428
|
-
return new Promise((resolve, reject) => {
|
|
1429
|
-
this.resolveStart = resolve;
|
|
1430
|
-
this.rejectStart = reject;
|
|
1431
|
-
if (this.binaryPath) {
|
|
1432
|
-
this.process = child_process.spawn(this.binaryPath, [], {
|
|
1433
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
1434
|
-
env: {
|
|
1435
|
-
...process.env,
|
|
1436
|
-
...this.env
|
|
1437
|
-
}
|
|
1438
|
-
});
|
|
1439
|
-
} else if (this.pythonFallback) {
|
|
1440
|
-
this.process = child_process.spawn(this.pythonFallback.command, this.pythonFallback.args, {
|
|
1441
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
1442
|
-
env: {
|
|
1443
|
-
...process.env,
|
|
1444
|
-
...this.env,
|
|
1445
|
-
PYTHONPATH: process.env.AGI_DRIVER_PATH ? `${process.env.AGI_DRIVER_PATH}/..` : ""
|
|
1446
|
-
},
|
|
1447
|
-
cwd: process.env.AGI_DRIVER_PATH ? `${process.env.AGI_DRIVER_PATH}/..` : void 0
|
|
1448
|
-
});
|
|
1449
|
-
} else {
|
|
1450
|
-
reject(new Error("No binary or Python fallback available"));
|
|
1451
|
-
return;
|
|
1452
|
-
}
|
|
1453
|
-
this.process.on("error", (err) => {
|
|
1454
|
-
this.cleanup();
|
|
1455
|
-
if (this.rejectStart) {
|
|
1456
|
-
this.rejectStart(err);
|
|
1457
|
-
this.rejectStart = null;
|
|
1458
|
-
this.resolveStart = null;
|
|
1459
|
-
}
|
|
1460
|
-
});
|
|
1461
|
-
this.process.on("exit", (code) => {
|
|
1462
|
-
this.cleanup();
|
|
1463
|
-
if (this.rejectStart) {
|
|
1464
|
-
this.rejectStart(new Error(`Driver exited with code ${code}`));
|
|
1465
|
-
this.rejectStart = null;
|
|
1466
|
-
this.resolveStart = null;
|
|
1467
|
-
}
|
|
1468
|
-
});
|
|
1469
|
-
this.readline = readline.createInterface({
|
|
1470
|
-
input: this.process.stdout,
|
|
1471
|
-
crlfDelay: Infinity
|
|
1472
|
-
});
|
|
1473
|
-
this.readline.on("line", (line) => {
|
|
1474
|
-
this.handleLine(line).catch((err) => {
|
|
1475
|
-
this.emit("error", {
|
|
1476
|
-
event: "error",
|
|
1477
|
-
message: `Error handling line: ${err.message}`,
|
|
1478
|
-
code: "parse_error",
|
|
1479
|
-
recoverable: false,
|
|
1480
|
-
step: this.step
|
|
1481
|
-
});
|
|
1482
|
-
});
|
|
1483
|
-
});
|
|
1484
|
-
this.process.stderr?.on("data", (data) => {
|
|
1485
|
-
this.emit("stderr", data.toString());
|
|
1486
|
-
});
|
|
1487
|
-
this.once("ready", () => {
|
|
1488
|
-
const startCmd = {
|
|
1489
|
-
command: "start",
|
|
1490
|
-
session_id: this.sessionId,
|
|
1491
|
-
goal,
|
|
1492
|
-
screenshot,
|
|
1493
|
-
screen_width: screenWidth,
|
|
1494
|
-
screen_height: screenHeight,
|
|
1495
|
-
platform: this.platform,
|
|
1496
|
-
model: this.model,
|
|
1497
|
-
mode: mode ?? this.mode
|
|
1498
|
-
};
|
|
1499
|
-
this.sendCommand(startCmd);
|
|
1500
|
-
});
|
|
1501
|
-
});
|
|
1502
|
-
}
|
|
1503
|
-
/**
|
|
1504
|
-
* Send a new screenshot to the driver.
|
|
1505
|
-
*
|
|
1506
|
-
* @param screenshot - Base64-encoded screenshot
|
|
1507
|
-
* @param screenWidth - Screen width in pixels
|
|
1508
|
-
* @param screenHeight - Screen height in pixels
|
|
1509
|
-
*/
|
|
1510
|
-
sendScreenshot(screenshot, screenWidth, screenHeight) {
|
|
1511
|
-
if (!this.process) {
|
|
1512
|
-
throw new Error("Driver is not running");
|
|
1513
|
-
}
|
|
1514
|
-
const cmd = {
|
|
1515
|
-
command: "screenshot",
|
|
1516
|
-
data: screenshot,
|
|
1517
|
-
screen_width: screenWidth ?? this.screenWidth,
|
|
1518
|
-
screen_height: screenHeight ?? this.screenHeight
|
|
1519
|
-
};
|
|
1520
|
-
this.sendCommand(cmd);
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Pause the driver.
|
|
1524
|
-
*/
|
|
1525
|
-
pause() {
|
|
1526
|
-
if (!this.process) return;
|
|
1527
|
-
this.sendCommand({ command: "pause" });
|
|
1528
|
-
}
|
|
1529
|
-
/**
|
|
1530
|
-
* Resume the driver.
|
|
1531
|
-
*/
|
|
1532
|
-
resume() {
|
|
1533
|
-
if (!this.process) return;
|
|
1534
|
-
this.sendCommand({ command: "resume" });
|
|
1535
|
-
}
|
|
1536
|
-
/**
|
|
1537
|
-
* Stop the driver.
|
|
1538
|
-
*
|
|
1539
|
-
* @param reason - Reason for stopping
|
|
1540
|
-
*/
|
|
1541
|
-
async stop(reason) {
|
|
1542
|
-
if (!this.process) return;
|
|
1543
|
-
const cmd = {
|
|
1544
|
-
command: "stop",
|
|
1545
|
-
reason
|
|
1546
|
-
};
|
|
1547
|
-
this.sendCommand(cmd);
|
|
1548
|
-
await new Promise((resolve) => {
|
|
1549
|
-
if (!this.process) {
|
|
1550
|
-
resolve();
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1553
|
-
this.process.once("exit", () => resolve());
|
|
1554
|
-
setTimeout(() => {
|
|
1555
|
-
if (this.process) {
|
|
1556
|
-
this.process.kill();
|
|
1557
|
-
}
|
|
1558
|
-
resolve();
|
|
1559
|
-
}, 1e3);
|
|
1560
|
-
});
|
|
1561
|
-
this.cleanup();
|
|
1562
|
-
}
|
|
1563
|
-
/**
|
|
1564
|
-
* Respond to a confirmation request.
|
|
1565
|
-
*
|
|
1566
|
-
* @param approved - Whether the action is approved
|
|
1567
|
-
* @param message - Optional message to send with the response
|
|
1568
|
-
*/
|
|
1569
|
-
respondConfirm(approved, message) {
|
|
1570
|
-
if (!this.process || this.state !== "waiting_confirmation") {
|
|
1571
|
-
throw new Error("Not waiting for confirmation");
|
|
1572
|
-
}
|
|
1573
|
-
const cmd = {
|
|
1574
|
-
command: "confirm",
|
|
1575
|
-
approved,
|
|
1576
|
-
message
|
|
1577
|
-
};
|
|
1578
|
-
this.sendCommand(cmd);
|
|
1579
|
-
if (this.pendingConfirm) {
|
|
1580
|
-
this.pendingConfirm(approved, message);
|
|
1581
|
-
this.pendingConfirm = null;
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
/**
|
|
1585
|
-
* Respond to a question.
|
|
1586
|
-
*
|
|
1587
|
-
* @param text - The answer text
|
|
1588
|
-
* @param questionId - Optional question ID
|
|
1589
|
-
*/
|
|
1590
|
-
respondAnswer(text, questionId) {
|
|
1591
|
-
if (!this.process || this.state !== "waiting_answer") {
|
|
1592
|
-
throw new Error("Not waiting for answer");
|
|
1593
|
-
}
|
|
1594
|
-
const cmd = {
|
|
1595
|
-
command: "answer",
|
|
1596
|
-
text,
|
|
1597
|
-
question_id: questionId
|
|
1598
|
-
};
|
|
1599
|
-
this.sendCommand(cmd);
|
|
1600
|
-
if (this.pendingAnswer) {
|
|
1601
|
-
this.pendingAnswer(text);
|
|
1602
|
-
this.pendingAnswer = null;
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
sendCommand(cmd) {
|
|
1606
|
-
if (!this.process?.stdin) return;
|
|
1607
|
-
const line = serializeCommand(cmd) + "\n";
|
|
1608
|
-
this.process.stdin.write(line);
|
|
1609
|
-
}
|
|
1610
|
-
async handleLine(line) {
|
|
1611
|
-
if (!line.trim()) return;
|
|
1612
|
-
let event;
|
|
1613
|
-
try {
|
|
1614
|
-
event = parseEvent(line);
|
|
1615
|
-
} catch (e) {
|
|
1616
|
-
console.error("Failed to parse event:", line);
|
|
1617
|
-
return;
|
|
1618
|
-
}
|
|
1619
|
-
this.step = event.step;
|
|
1620
|
-
this.emit("event", event);
|
|
1621
|
-
switch (event.event) {
|
|
1622
|
-
case "ready":
|
|
1623
|
-
this.emit("ready", event);
|
|
1624
|
-
break;
|
|
1625
|
-
case "state_change":
|
|
1626
|
-
this.state = event.state;
|
|
1627
|
-
this.emit("state_change", event.state, event);
|
|
1628
|
-
break;
|
|
1629
|
-
case "thinking":
|
|
1630
|
-
this.emit("thinking", event.text, event);
|
|
1631
|
-
break;
|
|
1632
|
-
case "action":
|
|
1633
|
-
this.emit("action", event.action, event);
|
|
1634
|
-
break;
|
|
1635
|
-
case "confirm": {
|
|
1636
|
-
this.state = "waiting_confirmation";
|
|
1637
|
-
const confirmListeners = this.rawListeners("confirm");
|
|
1638
|
-
let confirmHandled = false;
|
|
1639
|
-
for (const listener of confirmListeners) {
|
|
1640
|
-
try {
|
|
1641
|
-
const approved = await listener(event.reason, event);
|
|
1642
|
-
if (typeof approved === "boolean" && !confirmHandled) {
|
|
1643
|
-
this.respondConfirm(approved);
|
|
1644
|
-
confirmHandled = true;
|
|
1645
|
-
}
|
|
1646
|
-
} catch {
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
break;
|
|
1650
|
-
}
|
|
1651
|
-
case "ask_question": {
|
|
1652
|
-
this.state = "waiting_answer";
|
|
1653
|
-
const questionListeners = this.rawListeners("ask_question");
|
|
1654
|
-
let questionHandled = false;
|
|
1655
|
-
for (const listener of questionListeners) {
|
|
1656
|
-
try {
|
|
1657
|
-
const answer = await listener(event.question, event);
|
|
1658
|
-
if (typeof answer === "string" && !questionHandled) {
|
|
1659
|
-
this.respondAnswer(answer, event.question_id);
|
|
1660
|
-
questionHandled = true;
|
|
1661
|
-
}
|
|
1662
|
-
} catch {
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
break;
|
|
1666
|
-
}
|
|
1667
|
-
case "screenshot_captured":
|
|
1668
|
-
this.emit("screenshot_captured", event);
|
|
1669
|
-
break;
|
|
1670
|
-
case "finished":
|
|
1671
|
-
this.handleFinished(event);
|
|
1672
|
-
break;
|
|
1673
|
-
case "error":
|
|
1674
|
-
this.handleError(event);
|
|
1675
|
-
break;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
handleFinished(event) {
|
|
1679
|
-
this.state = "finished";
|
|
1680
|
-
this.emit("finished", event);
|
|
1681
|
-
if (this.resolveStart) {
|
|
1682
|
-
this.resolveStart({
|
|
1683
|
-
success: event.success,
|
|
1684
|
-
reason: event.reason,
|
|
1685
|
-
summary: event.summary,
|
|
1686
|
-
step: event.step
|
|
1687
|
-
});
|
|
1688
|
-
this.resolveStart = null;
|
|
1689
|
-
this.rejectStart = null;
|
|
1690
|
-
}
|
|
1691
|
-
this.cleanup();
|
|
1692
|
-
}
|
|
1693
|
-
handleError(event) {
|
|
1694
|
-
this.emit("error", event);
|
|
1695
|
-
if (!event.recoverable) {
|
|
1696
|
-
this.state = "error";
|
|
1697
|
-
if (this.rejectStart) {
|
|
1698
|
-
this.rejectStart(new Error(`${event.code}: ${event.message}`));
|
|
1699
|
-
this.rejectStart = null;
|
|
1700
|
-
this.resolveStart = null;
|
|
1701
|
-
}
|
|
1702
|
-
this.cleanup();
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
cleanup() {
|
|
1706
|
-
if (this.readline) {
|
|
1707
|
-
this.readline.close();
|
|
1708
|
-
this.readline = null;
|
|
1709
|
-
}
|
|
1710
|
-
if (this.rejectStart) {
|
|
1711
|
-
this.rejectStart(new Error("Driver stopped"));
|
|
1712
|
-
this.rejectStart = null;
|
|
1713
|
-
this.resolveStart = null;
|
|
1714
|
-
}
|
|
1715
|
-
if (this.process) {
|
|
1716
|
-
this.process.kill();
|
|
1717
|
-
this.process = null;
|
|
1718
|
-
}
|
|
1719
|
-
this.pendingConfirm = null;
|
|
1720
|
-
this.pendingAnswer = null;
|
|
1721
|
-
}
|
|
1722
|
-
};
|
|
1723
|
-
|
|
1724
|
-
exports.AGIClient = AGIClient;
|
|
1725
|
-
exports.AGIError = AGIError;
|
|
1726
|
-
exports.APIError = APIError;
|
|
1727
|
-
exports.AgentDriver = AgentDriver;
|
|
1728
|
-
exports.AgentExecutionError = AgentExecutionError;
|
|
1729
|
-
exports.AgentLoop = AgentLoop;
|
|
1730
|
-
exports.AuthenticationError = AuthenticationError;
|
|
1731
|
-
exports.NotFoundError = NotFoundError;
|
|
1732
|
-
exports.PermissionError = PermissionError;
|
|
1733
|
-
exports.RateLimitError = RateLimitError;
|
|
1734
|
-
exports.Screenshot = Screenshot;
|
|
1735
|
-
exports.SessionContext = SessionContext;
|
|
1736
|
-
exports.SessionsResource = SessionsResource;
|
|
1737
|
-
exports.ValidationError = ValidationError;
|
|
1738
|
-
exports.findBinaryPath = findBinaryPath;
|
|
1739
|
-
exports.getPlatformId = getPlatformId;
|
|
1740
|
-
exports.isBinaryAvailable = isBinaryAvailable;
|
|
1741
|
-
//# sourceMappingURL=index.js.map
|
|
1742
|
-
//# sourceMappingURL=index.js.map
|