agi 0.2.2 → 0.3.0
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/LICENSE +21 -0
- package/README.md +463 -14
- package/dist/index.d.mts +824 -0
- package/dist/index.d.ts +824 -0
- package/dist/index.js +959 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +946 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +68 -32
- package/LICENSE.pdf +0 -0
- package/scripts/install-dmg.js +0 -74
package/dist/index.js
ADDED
|
@@ -0,0 +1,959 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var eventsourceParser = require('eventsource-parser');
|
|
4
|
+
|
|
5
|
+
// src/http.ts
|
|
6
|
+
|
|
7
|
+
// src/errors.ts
|
|
8
|
+
var AGIError = class _AGIError extends Error {
|
|
9
|
+
constructor(message, statusCode, response) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
this.response = response;
|
|
13
|
+
this.name = "AGIError";
|
|
14
|
+
Object.setPrototypeOf(this, _AGIError.prototype);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var AuthenticationError = class _AuthenticationError extends AGIError {
|
|
18
|
+
constructor(message, response) {
|
|
19
|
+
super(message, 401, response);
|
|
20
|
+
this.name = "AuthenticationError";
|
|
21
|
+
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var NotFoundError = class _NotFoundError extends AGIError {
|
|
25
|
+
constructor(message, response) {
|
|
26
|
+
super(message, 404, response);
|
|
27
|
+
this.name = "NotFoundError";
|
|
28
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var RateLimitError = class _RateLimitError extends AGIError {
|
|
32
|
+
constructor(message, response) {
|
|
33
|
+
super(message, 429, response);
|
|
34
|
+
this.name = "RateLimitError";
|
|
35
|
+
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var AgentExecutionError = class _AgentExecutionError extends AGIError {
|
|
39
|
+
constructor(message, response) {
|
|
40
|
+
super(message, void 0, response);
|
|
41
|
+
this.name = "AgentExecutionError";
|
|
42
|
+
Object.setPrototypeOf(this, _AgentExecutionError.prototype);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var ValidationError = class _ValidationError extends AGIError {
|
|
46
|
+
constructor(message, response) {
|
|
47
|
+
super(message, 422, response);
|
|
48
|
+
this.name = "ValidationError";
|
|
49
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var PermissionError = class _PermissionError extends AGIError {
|
|
53
|
+
constructor(message, response) {
|
|
54
|
+
super(message, 403, response);
|
|
55
|
+
this.name = "PermissionError";
|
|
56
|
+
Object.setPrototypeOf(this, _PermissionError.prototype);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var APIError = class _APIError extends AGIError {
|
|
60
|
+
constructor(message, statusCode, response) {
|
|
61
|
+
super(message, statusCode, response);
|
|
62
|
+
this.name = "APIError";
|
|
63
|
+
Object.setPrototypeOf(this, _APIError.prototype);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/http.ts
|
|
68
|
+
var HTTPClient = class {
|
|
69
|
+
apiKey;
|
|
70
|
+
baseUrl;
|
|
71
|
+
timeout;
|
|
72
|
+
maxRetries;
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.apiKey = options.apiKey;
|
|
75
|
+
this.baseUrl = options.baseUrl ?? "https://api.agi.tech";
|
|
76
|
+
this.timeout = options.timeout ?? 6e4;
|
|
77
|
+
this.maxRetries = options.maxRetries ?? 3;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Make an HTTP request with retries and error handling
|
|
81
|
+
*/
|
|
82
|
+
async request(method, path, options) {
|
|
83
|
+
const url = this.buildUrl(path, options?.query);
|
|
84
|
+
const headers = this.buildHeaders(options?.headers);
|
|
85
|
+
let lastError;
|
|
86
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
87
|
+
try {
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
90
|
+
const response = await fetch(url, {
|
|
91
|
+
method,
|
|
92
|
+
headers,
|
|
93
|
+
body: options?.json ? JSON.stringify(options.json) : void 0,
|
|
94
|
+
signal: controller.signal
|
|
95
|
+
});
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
await this.handleErrorResponse(response);
|
|
99
|
+
}
|
|
100
|
+
const data = await response.json();
|
|
101
|
+
return data;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
lastError = error;
|
|
104
|
+
if (error instanceof AGIError && error.statusCode && error.statusCode < 500) {
|
|
105
|
+
if (error.statusCode !== 429) {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (attempt === this.maxRetries) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
await this.sleep(Math.pow(2, attempt) * 1e3);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw lastError || new AGIError("Request failed after retries");
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stream Server-Sent Events from an endpoint
|
|
119
|
+
*/
|
|
120
|
+
async *streamEvents(path, query) {
|
|
121
|
+
const url = this.buildUrl(path, query);
|
|
122
|
+
const headers = this.buildHeaders();
|
|
123
|
+
const controller = new AbortController();
|
|
124
|
+
const response = await fetch(url, {
|
|
125
|
+
method: "GET",
|
|
126
|
+
headers: {
|
|
127
|
+
...headers,
|
|
128
|
+
Accept: "text/event-stream"
|
|
129
|
+
},
|
|
130
|
+
signal: controller.signal
|
|
131
|
+
});
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
await this.handleErrorResponse(response);
|
|
134
|
+
}
|
|
135
|
+
if (!response.body) {
|
|
136
|
+
throw new AGIError("Response body is null");
|
|
137
|
+
}
|
|
138
|
+
const reader = response.body.getReader();
|
|
139
|
+
const decoder = new TextDecoder();
|
|
140
|
+
let buffer = "";
|
|
141
|
+
const parser = eventsourceParser.createParser((event) => {
|
|
142
|
+
if (event.type === "event") {
|
|
143
|
+
try {
|
|
144
|
+
const data = JSON.parse(event.data);
|
|
145
|
+
this.pendingEvents.push({
|
|
146
|
+
id: event.id,
|
|
147
|
+
event: event.event,
|
|
148
|
+
data
|
|
149
|
+
});
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
const pendingEvents = [];
|
|
155
|
+
this.pendingEvents = pendingEvents;
|
|
156
|
+
try {
|
|
157
|
+
while (true) {
|
|
158
|
+
const { done, value } = await reader.read();
|
|
159
|
+
if (done) {
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
buffer += decoder.decode(value, { stream: true });
|
|
163
|
+
parser.feed(buffer);
|
|
164
|
+
buffer = "";
|
|
165
|
+
while (pendingEvents.length > 0) {
|
|
166
|
+
const event = pendingEvents.shift();
|
|
167
|
+
if (event) {
|
|
168
|
+
yield event;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} finally {
|
|
173
|
+
controller.abort();
|
|
174
|
+
reader.releaseLock();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
pendingEvents = [];
|
|
178
|
+
buildUrl(path, query) {
|
|
179
|
+
const url = new URL(path, this.baseUrl);
|
|
180
|
+
if (query) {
|
|
181
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
182
|
+
url.searchParams.append(key, value);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return url.toString();
|
|
186
|
+
}
|
|
187
|
+
buildHeaders(additional) {
|
|
188
|
+
return {
|
|
189
|
+
"Content-Type": "application/json",
|
|
190
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
191
|
+
"User-Agent": "agi-sdk-node/1.0.0",
|
|
192
|
+
...additional
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
async handleErrorResponse(response) {
|
|
196
|
+
let errorData;
|
|
197
|
+
try {
|
|
198
|
+
errorData = await response.json();
|
|
199
|
+
} catch {
|
|
200
|
+
errorData = await response.text();
|
|
201
|
+
}
|
|
202
|
+
const errorMessage = typeof errorData === "object" && errorData.message ? errorData.message : typeof errorData === "string" ? errorData : `HTTP ${response.status}: ${response.statusText}`;
|
|
203
|
+
switch (response.status) {
|
|
204
|
+
case 401:
|
|
205
|
+
throw new AuthenticationError(`Authentication failed: ${errorMessage}`, errorData);
|
|
206
|
+
case 403:
|
|
207
|
+
throw new PermissionError(`Permission denied: ${errorMessage}`, errorData);
|
|
208
|
+
case 404:
|
|
209
|
+
throw new NotFoundError(`Resource not found: ${errorMessage}`, errorData);
|
|
210
|
+
case 422:
|
|
211
|
+
throw new ValidationError(`Validation error: ${errorMessage}`, errorData);
|
|
212
|
+
case 429:
|
|
213
|
+
throw new RateLimitError(`Rate limit exceeded: ${errorMessage}`, errorData);
|
|
214
|
+
default:
|
|
215
|
+
if (response.status >= 500) {
|
|
216
|
+
throw new APIError(
|
|
217
|
+
`Server error (${response.status}): ${errorMessage}`,
|
|
218
|
+
response.status,
|
|
219
|
+
errorData
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
throw new AGIError(
|
|
223
|
+
`API error (${response.status}): ${errorMessage}`,
|
|
224
|
+
response.status,
|
|
225
|
+
errorData
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
sleep(ms) {
|
|
230
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// src/types/screenshot.ts
|
|
235
|
+
var Screenshot = class _Screenshot {
|
|
236
|
+
constructor(data, format, timestamp, width, height, url, title) {
|
|
237
|
+
this.data = data;
|
|
238
|
+
this.format = format;
|
|
239
|
+
this.timestamp = timestamp;
|
|
240
|
+
this.width = width;
|
|
241
|
+
this.height = height;
|
|
242
|
+
this.url = url;
|
|
243
|
+
this.title = title;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Save screenshot to file
|
|
247
|
+
*
|
|
248
|
+
* @param path - File path to save to (e.g., "screenshot.png")
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* const screenshot = await session.screenshot();
|
|
253
|
+
* await screenshot.save("amazon.png");
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
async save(path) {
|
|
257
|
+
const fs = await import('fs/promises');
|
|
258
|
+
await fs.writeFile(path, this.data);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Create Screenshot from base64 data URL
|
|
262
|
+
*
|
|
263
|
+
* @param base64Data - Base64-encoded data URL (e.g., "data:image/jpeg;base64,...")
|
|
264
|
+
* @param url - Current page URL
|
|
265
|
+
* @param title - Current page title
|
|
266
|
+
* @param timestamp - Screenshot timestamp (defaults to now)
|
|
267
|
+
* @returns Screenshot instance with decoded image data
|
|
268
|
+
*/
|
|
269
|
+
static fromBase64(base64Data, url, title, timestamp) {
|
|
270
|
+
let header;
|
|
271
|
+
let encoded;
|
|
272
|
+
if (base64Data.includes(",")) {
|
|
273
|
+
[header, encoded] = base64Data.split(",", 2);
|
|
274
|
+
} else {
|
|
275
|
+
encoded = base64Data;
|
|
276
|
+
header = "data:image/png;base64";
|
|
277
|
+
}
|
|
278
|
+
const imageData = Buffer.from(encoded, "base64");
|
|
279
|
+
const format = header.toLowerCase().includes("jpeg") || header.toLowerCase().includes("jpg") ? "jpg" : "png";
|
|
280
|
+
const { width, height } = _Screenshot.getImageDimensions(imageData, format);
|
|
281
|
+
return new _Screenshot(imageData, format, timestamp || /* @__PURE__ */ new Date(), width, height, url, title);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Extract width and height from image data
|
|
285
|
+
*
|
|
286
|
+
* @param data - Raw image bytes
|
|
287
|
+
* @param format - Image format (png, jpg)
|
|
288
|
+
* @returns Tuple of (width, height)
|
|
289
|
+
*/
|
|
290
|
+
static getImageDimensions(data, format) {
|
|
291
|
+
try {
|
|
292
|
+
if (format === "png" && data.length >= 24) {
|
|
293
|
+
const width = data.readUInt32BE(16);
|
|
294
|
+
const height = data.readUInt32BE(20);
|
|
295
|
+
return { width, height };
|
|
296
|
+
} else if (format === "jpg") {
|
|
297
|
+
for (let i = 0; i < data.length - 9; i++) {
|
|
298
|
+
if (data[i] === 255 && data[i + 1] === 192) {
|
|
299
|
+
const height = data.readUInt16BE(i + 5);
|
|
300
|
+
const width = data.readUInt16BE(i + 7);
|
|
301
|
+
return { width, height };
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch (error) {
|
|
306
|
+
}
|
|
307
|
+
return { width: 0, height: 0 };
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/context/session-context.ts
|
|
312
|
+
var SessionContext = class {
|
|
313
|
+
constructor(client, agentName = "agi-0", createOptions) {
|
|
314
|
+
this.client = client;
|
|
315
|
+
this.agentName = agentName;
|
|
316
|
+
this.createOptions = createOptions;
|
|
317
|
+
}
|
|
318
|
+
sessionId;
|
|
319
|
+
vncUrl;
|
|
320
|
+
agentUrl;
|
|
321
|
+
/**
|
|
322
|
+
* Automatic cleanup via explicit resource management
|
|
323
|
+
*/
|
|
324
|
+
async [Symbol.asyncDispose]() {
|
|
325
|
+
if (this.sessionId) {
|
|
326
|
+
try {
|
|
327
|
+
await this.client.sessions.delete(this.sessionId);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Ensure session is created
|
|
334
|
+
*/
|
|
335
|
+
async ensureSession() {
|
|
336
|
+
if (this.sessionId) return;
|
|
337
|
+
const response = await this.client.sessions.create(this.agentName, this.createOptions);
|
|
338
|
+
this.sessionId = response.sessionId;
|
|
339
|
+
this.vncUrl = response.vncUrl;
|
|
340
|
+
this.agentUrl = response.agentUrl;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Run a task and wait for completion using HTTP polling
|
|
344
|
+
*
|
|
345
|
+
* This method uses HTTP polling instead of SSE streaming for better reliability
|
|
346
|
+
* with long-running tasks and network instability.
|
|
347
|
+
*
|
|
348
|
+
* @param task - Natural language task description
|
|
349
|
+
* @param options - Task execution options
|
|
350
|
+
* @returns TaskResult with data and execution metadata
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* const result = await session.runTask(
|
|
355
|
+
* 'Find cheapest iPhone 15 Pro',
|
|
356
|
+
* { timeout: 300000, pollInterval: 2000 } // 5 min timeout, 2s polling
|
|
357
|
+
* );
|
|
358
|
+
* console.log(result.data);
|
|
359
|
+
* console.log(`Took ${result.metadata.duration}s, ${result.metadata.steps} steps`);
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
async runTask(task, options) {
|
|
363
|
+
await this.ensureSession();
|
|
364
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
365
|
+
const timeout = options?.timeout ?? 6e5;
|
|
366
|
+
const pollInterval = options?.pollInterval ?? 3e3;
|
|
367
|
+
await this.client.sessions.sendMessage(this.sessionId, task, {
|
|
368
|
+
startUrl: options?.startUrl
|
|
369
|
+
});
|
|
370
|
+
const startTime = Date.now();
|
|
371
|
+
while (true) {
|
|
372
|
+
const elapsed = Date.now() - startTime;
|
|
373
|
+
if (elapsed > timeout) {
|
|
374
|
+
throw new AgentExecutionError(
|
|
375
|
+
`Task exceeded timeout of ${timeout}ms (elapsed: ${elapsed}ms)`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
const statusResponse = await this.client.sessions.getStatus(this.sessionId);
|
|
379
|
+
if (statusResponse.status === "finished" || statusResponse.status === "waiting_for_input") {
|
|
380
|
+
const messagesResponse = await this.client.sessions.getMessages(this.sessionId);
|
|
381
|
+
const messages = messagesResponse.messages;
|
|
382
|
+
const doneMsg = messages.find((msg) => msg.type === "DONE" || msg.type === "QUESTION");
|
|
383
|
+
if (!doneMsg) {
|
|
384
|
+
throw new AgentExecutionError(
|
|
385
|
+
`Task status '${statusResponse.status}' but no DONE/QUESTION message found`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
const content = doneMsg.content;
|
|
389
|
+
const data = typeof content === "object" && content !== null ? content : { content: content ?? {} };
|
|
390
|
+
const duration = (Date.now() - startTime) / 1e3;
|
|
391
|
+
const steps = messages.filter(
|
|
392
|
+
(msg) => ["THOUGHT", "QUESTION", "DONE"].includes(msg.type)
|
|
393
|
+
).length;
|
|
394
|
+
const metadata = {
|
|
395
|
+
taskId: doneMsg.id,
|
|
396
|
+
sessionId: this.sessionId,
|
|
397
|
+
duration,
|
|
398
|
+
cost: 0,
|
|
399
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
400
|
+
steps,
|
|
401
|
+
success: true
|
|
402
|
+
};
|
|
403
|
+
return { data, metadata };
|
|
404
|
+
}
|
|
405
|
+
if (statusResponse.status === "error") {
|
|
406
|
+
const messagesResponse = await this.client.sessions.getMessages(this.sessionId);
|
|
407
|
+
const errorMsg = messagesResponse.messages.find((msg) => msg.type === "ERROR");
|
|
408
|
+
const errorDetails = errorMsg ? typeof errorMsg.content === "string" ? errorMsg.content : JSON.stringify(errorMsg.content) : "Unknown error";
|
|
409
|
+
throw new AgentExecutionError(`Task failed: ${errorDetails}`);
|
|
410
|
+
}
|
|
411
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Send a message to the agent
|
|
416
|
+
*
|
|
417
|
+
* @param message - Message content
|
|
418
|
+
* @param options - Message options
|
|
419
|
+
* @returns SuccessResponse confirming message was sent
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* await session.sendMessage('Find flights from SFO to JFK under $450');
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
async sendMessage(message, options) {
|
|
427
|
+
await this.ensureSession();
|
|
428
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
429
|
+
return this.client.sessions.sendMessage(this.sessionId, message, options);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Get current execution status
|
|
433
|
+
*
|
|
434
|
+
* @returns ExecuteStatusResponse with status
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* ```typescript
|
|
438
|
+
* const status = await session.getStatus();
|
|
439
|
+
* console.log(status.status);
|
|
440
|
+
* ```
|
|
441
|
+
*/
|
|
442
|
+
async getStatus() {
|
|
443
|
+
await this.ensureSession();
|
|
444
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
445
|
+
return this.client.sessions.getStatus(this.sessionId);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Get messages from the session
|
|
449
|
+
*
|
|
450
|
+
* @param afterId - Return messages with ID > afterId (for polling)
|
|
451
|
+
* @param sanitize - Filter out system messages, prompts, and images
|
|
452
|
+
* @returns MessagesResponse with messages list and status
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* const messages = await session.getMessages(0);
|
|
457
|
+
* for (const msg of messages.messages) {
|
|
458
|
+
* console.log(`[${msg.type}] ${msg.content}`);
|
|
459
|
+
* }
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
async getMessages(afterId, sanitize = true) {
|
|
463
|
+
await this.ensureSession();
|
|
464
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
465
|
+
return this.client.sessions.getMessages(this.sessionId, afterId, sanitize);
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Stream real-time events from the session via Server-Sent Events
|
|
469
|
+
*
|
|
470
|
+
* @param options - Stream options
|
|
471
|
+
* @yields SSEEvent objects
|
|
472
|
+
*
|
|
473
|
+
* @example
|
|
474
|
+
* ```typescript
|
|
475
|
+
* for await (const event of session.streamEvents()) {
|
|
476
|
+
* if (event.event === 'thought') {
|
|
477
|
+
* console.log('Agent:', event.data);
|
|
478
|
+
* }
|
|
479
|
+
* if (event.event === 'done') {
|
|
480
|
+
* console.log('Result:', event.data);
|
|
481
|
+
* break;
|
|
482
|
+
* }
|
|
483
|
+
* }
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
async *streamEvents(options) {
|
|
487
|
+
await this.ensureSession();
|
|
488
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
489
|
+
yield* this.client.sessions.streamEvents(this.sessionId, options);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Pause task execution
|
|
493
|
+
*
|
|
494
|
+
* @returns SuccessResponse confirming pause
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* await session.pause();
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
async pause() {
|
|
502
|
+
await this.ensureSession();
|
|
503
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
504
|
+
return this.client.sessions.pause(this.sessionId);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Resume paused task
|
|
508
|
+
*
|
|
509
|
+
* @returns SuccessResponse confirming resume
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* ```typescript
|
|
513
|
+
* await session.resume();
|
|
514
|
+
* ```
|
|
515
|
+
*/
|
|
516
|
+
async resume() {
|
|
517
|
+
await this.ensureSession();
|
|
518
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
519
|
+
return this.client.sessions.resume(this.sessionId);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Cancel task execution
|
|
523
|
+
*
|
|
524
|
+
* @returns SuccessResponse confirming cancellation
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* await session.cancel();
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
async cancel() {
|
|
532
|
+
await this.ensureSession();
|
|
533
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
534
|
+
return this.client.sessions.cancel(this.sessionId);
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Navigate browser to URL
|
|
538
|
+
*
|
|
539
|
+
* @param url - URL to navigate to
|
|
540
|
+
* @returns NavigateResponse with current URL
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```typescript
|
|
544
|
+
* await session.navigate('https://amazon.com');
|
|
545
|
+
* ```
|
|
546
|
+
*/
|
|
547
|
+
async navigate(url) {
|
|
548
|
+
await this.ensureSession();
|
|
549
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
550
|
+
return this.client.sessions.navigate(this.sessionId, url);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Get browser screenshot
|
|
554
|
+
*
|
|
555
|
+
* @returns Screenshot with decoded image data and save() method
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```typescript
|
|
559
|
+
* const screenshot = await session.screenshot();
|
|
560
|
+
* await screenshot.save('page.png');
|
|
561
|
+
* console.log(`Size: ${screenshot.width}x${screenshot.height}`);
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
async screenshot() {
|
|
565
|
+
await this.ensureSession();
|
|
566
|
+
if (!this.sessionId) throw new Error("Session not created");
|
|
567
|
+
const response = await this.client.sessions.screenshot(this.sessionId);
|
|
568
|
+
return Screenshot.fromBase64(response.screenshot, response.url, response.title);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/utils.ts
|
|
573
|
+
function normalizeSessionResponse(data) {
|
|
574
|
+
return {
|
|
575
|
+
sessionId: data.session_id ?? data.sessionId,
|
|
576
|
+
vncUrl: data.vnc_url ?? data.vncUrl,
|
|
577
|
+
agentUrl: data.agent_url ?? data.agentUrl,
|
|
578
|
+
agentName: data.agent_name ?? data.agentName,
|
|
579
|
+
status: data.status,
|
|
580
|
+
createdAt: data.created_at ?? data.createdAt,
|
|
581
|
+
environmentId: data.environment_id ?? data.environmentId,
|
|
582
|
+
goal: data.goal
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/resources/sessions.ts
|
|
587
|
+
var SessionsResource = class {
|
|
588
|
+
constructor(http) {
|
|
589
|
+
this.http = http;
|
|
590
|
+
}
|
|
591
|
+
// ===== SESSION MANAGEMENT =====
|
|
592
|
+
/**
|
|
593
|
+
* Create a new agent session
|
|
594
|
+
*
|
|
595
|
+
* @param agentName - Agent model to use (e.g., "agi-0", "agi-0-fast", "agi-1")
|
|
596
|
+
* @param options - Session creation options
|
|
597
|
+
* @returns SessionResponse with session_id, vnc_url, status, etc.
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```typescript
|
|
601
|
+
* const session = await client.sessions.create('agi-0', {
|
|
602
|
+
* webhookUrl: 'https://yourapp.com/webhook',
|
|
603
|
+
* maxSteps: 200
|
|
604
|
+
* });
|
|
605
|
+
* ```
|
|
606
|
+
*/
|
|
607
|
+
async create(agentName = "agi-0", options) {
|
|
608
|
+
const payload = {
|
|
609
|
+
agent_name: agentName,
|
|
610
|
+
max_steps: options?.maxSteps ?? 100
|
|
611
|
+
};
|
|
612
|
+
if (options?.webhookUrl) payload.webhook_url = options.webhookUrl;
|
|
613
|
+
if (options?.goal) payload.goal = options.goal;
|
|
614
|
+
if (options?.restoreFromEnvironmentId) {
|
|
615
|
+
payload.restore_from_environment_id = options.restoreFromEnvironmentId;
|
|
616
|
+
}
|
|
617
|
+
const response = await this.http.request("POST", "/v1/sessions", {
|
|
618
|
+
json: payload
|
|
619
|
+
});
|
|
620
|
+
return normalizeSessionResponse(response);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* List all sessions for the authenticated user
|
|
624
|
+
*
|
|
625
|
+
* @returns Array of SessionResponse objects
|
|
626
|
+
*
|
|
627
|
+
* @example
|
|
628
|
+
* ```typescript
|
|
629
|
+
* const sessions = await client.sessions.list();
|
|
630
|
+
* for (const session of sessions) {
|
|
631
|
+
* console.log(`${session.sessionId}: ${session.status}`);
|
|
632
|
+
* }
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
async list() {
|
|
636
|
+
const responses = await this.http.request(
|
|
637
|
+
"GET",
|
|
638
|
+
"/v1/sessions"
|
|
639
|
+
);
|
|
640
|
+
return responses.map(normalizeSessionResponse);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Get details for a specific session
|
|
644
|
+
*
|
|
645
|
+
* @param sessionId - Session UUID
|
|
646
|
+
* @returns SessionResponse with session details
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* const session = await client.sessions.get('session-uuid');
|
|
651
|
+
* console.log(session.status);
|
|
652
|
+
* ```
|
|
653
|
+
*/
|
|
654
|
+
async get(sessionId) {
|
|
655
|
+
const response = await this.http.request(
|
|
656
|
+
"GET",
|
|
657
|
+
`/v1/sessions/${sessionId}`
|
|
658
|
+
);
|
|
659
|
+
return normalizeSessionResponse(response);
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Delete a session and cleanup its resources
|
|
663
|
+
*
|
|
664
|
+
* @param sessionId - Session UUID
|
|
665
|
+
* @param saveSnapshotMode - Snapshot mode: "none", "memory", or "filesystem"
|
|
666
|
+
* @returns DeleteResponse confirming deletion
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```typescript
|
|
670
|
+
* await client.sessions.delete('session-uuid', 'filesystem');
|
|
671
|
+
* ```
|
|
672
|
+
*/
|
|
673
|
+
async delete(sessionId, saveSnapshotMode = "none") {
|
|
674
|
+
return this.http.request("DELETE", `/v1/sessions/${sessionId}`, {
|
|
675
|
+
query: { save_snapshot_mode: saveSnapshotMode }
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Delete all sessions for the authenticated user
|
|
680
|
+
*
|
|
681
|
+
* @returns DeleteResponse with count of deleted sessions
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* const result = await client.sessions.deleteAll();
|
|
686
|
+
* console.log(result.message);
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
689
|
+
async deleteAll() {
|
|
690
|
+
return this.http.request("DELETE", "/v1/sessions");
|
|
691
|
+
}
|
|
692
|
+
// ===== AGENT INTERACTION =====
|
|
693
|
+
/**
|
|
694
|
+
* Send a message to the agent to start a task or respond to questions
|
|
695
|
+
*
|
|
696
|
+
* @param sessionId - Session UUID
|
|
697
|
+
* @param message - Message content (task instruction or response)
|
|
698
|
+
* @param options - Message options
|
|
699
|
+
* @returns SuccessResponse confirming message was sent
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* ```typescript
|
|
703
|
+
* await client.sessions.sendMessage(
|
|
704
|
+
* 'session-uuid',
|
|
705
|
+
* 'Find flights from SFO to JFK under $450'
|
|
706
|
+
* );
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
async sendMessage(sessionId, message, options) {
|
|
710
|
+
return this.http.request("POST", `/v1/sessions/${sessionId}/message`, {
|
|
711
|
+
json: {
|
|
712
|
+
message,
|
|
713
|
+
start_url: options?.startUrl,
|
|
714
|
+
config_updates: options?.configUpdates
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Get the current execution status of a session
|
|
720
|
+
*
|
|
721
|
+
* @param sessionId - Session UUID
|
|
722
|
+
* @returns ExecuteStatusResponse with status
|
|
723
|
+
*
|
|
724
|
+
* @example
|
|
725
|
+
* ```typescript
|
|
726
|
+
* const status = await client.sessions.getStatus('session-uuid');
|
|
727
|
+
* if (status.status === 'finished') {
|
|
728
|
+
* console.log('Task completed!');
|
|
729
|
+
* }
|
|
730
|
+
* ```
|
|
731
|
+
*/
|
|
732
|
+
async getStatus(sessionId) {
|
|
733
|
+
return this.http.request("GET", `/v1/sessions/${sessionId}/status`);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Poll for messages and updates from the agent
|
|
737
|
+
*
|
|
738
|
+
* @param sessionId - Session UUID
|
|
739
|
+
* @param afterId - Return messages with ID > afterId (for polling)
|
|
740
|
+
* @param sanitize - Filter out system messages, prompts, and images
|
|
741
|
+
* @returns MessagesResponse with messages list and status
|
|
742
|
+
*
|
|
743
|
+
* @example
|
|
744
|
+
* ```typescript
|
|
745
|
+
* const messages = await client.sessions.getMessages('session-uuid', 0);
|
|
746
|
+
* for (const msg of messages.messages) {
|
|
747
|
+
* console.log(`[${msg.type}] ${msg.content}`);
|
|
748
|
+
* }
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
async getMessages(sessionId, afterId = 0, sanitize = true) {
|
|
752
|
+
const response = await this.http.request(
|
|
753
|
+
"GET",
|
|
754
|
+
`/v1/sessions/${sessionId}/messages`,
|
|
755
|
+
{
|
|
756
|
+
query: {
|
|
757
|
+
after_id: String(afterId),
|
|
758
|
+
sanitize: String(sanitize)
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
);
|
|
762
|
+
return {
|
|
763
|
+
messages: response.messages || [],
|
|
764
|
+
status: response.status,
|
|
765
|
+
hasAgent: response.has_agent ?? response.hasAgent ?? false
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Stream real-time events from the session via Server-Sent Events
|
|
770
|
+
*
|
|
771
|
+
* @param sessionId - Session UUID
|
|
772
|
+
* @param options - Stream options
|
|
773
|
+
* @yields SSEEvent objects
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* ```typescript
|
|
777
|
+
* for await (const event of client.sessions.streamEvents('session-uuid')) {
|
|
778
|
+
* if (event.event === 'thought') {
|
|
779
|
+
* console.log('Agent:', event.data);
|
|
780
|
+
* }
|
|
781
|
+
* if (event.event === 'done') {
|
|
782
|
+
* console.log('Result:', event.data);
|
|
783
|
+
* break;
|
|
784
|
+
* }
|
|
785
|
+
* }
|
|
786
|
+
* ```
|
|
787
|
+
*/
|
|
788
|
+
async *streamEvents(sessionId, options) {
|
|
789
|
+
const query = {
|
|
790
|
+
sanitize: String(options?.sanitize ?? true),
|
|
791
|
+
include_history: String(options?.includeHistory ?? true)
|
|
792
|
+
};
|
|
793
|
+
if (options?.eventTypes) {
|
|
794
|
+
query.event_types = options.eventTypes.join(",");
|
|
795
|
+
}
|
|
796
|
+
yield* this.http.streamEvents(`/v1/sessions/${sessionId}/events`, query);
|
|
797
|
+
}
|
|
798
|
+
// ===== SESSION CONTROL =====
|
|
799
|
+
/**
|
|
800
|
+
* Temporarily pause task execution
|
|
801
|
+
*
|
|
802
|
+
* @param sessionId - Session UUID
|
|
803
|
+
* @returns SuccessResponse confirming pause
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```typescript
|
|
807
|
+
* await client.sessions.pause('session-uuid');
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
async pause(sessionId) {
|
|
811
|
+
return this.http.request("POST", `/v1/sessions/${sessionId}/pause`);
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Resume a paused task
|
|
815
|
+
*
|
|
816
|
+
* @param sessionId - Session UUID
|
|
817
|
+
* @returns SuccessResponse confirming resume
|
|
818
|
+
*
|
|
819
|
+
* @example
|
|
820
|
+
* ```typescript
|
|
821
|
+
* await client.sessions.resume('session-uuid');
|
|
822
|
+
* ```
|
|
823
|
+
*/
|
|
824
|
+
async resume(sessionId) {
|
|
825
|
+
return this.http.request("POST", `/v1/sessions/${sessionId}/resume`);
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Cancel task execution
|
|
829
|
+
*
|
|
830
|
+
* @param sessionId - Session UUID
|
|
831
|
+
* @returns SuccessResponse confirming cancellation
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* ```typescript
|
|
835
|
+
* await client.sessions.cancel('session-uuid');
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
async cancel(sessionId) {
|
|
839
|
+
return this.http.request("POST", `/v1/sessions/${sessionId}/cancel`);
|
|
840
|
+
}
|
|
841
|
+
// ===== BROWSER CONTROL =====
|
|
842
|
+
/**
|
|
843
|
+
* Navigate the browser to a specific URL
|
|
844
|
+
*
|
|
845
|
+
* @param sessionId - Session UUID
|
|
846
|
+
* @param url - URL to navigate to
|
|
847
|
+
* @returns NavigateResponse with current URL
|
|
848
|
+
*
|
|
849
|
+
* @example
|
|
850
|
+
* ```typescript
|
|
851
|
+
* await client.sessions.navigate('session-uuid', 'https://amazon.com');
|
|
852
|
+
* ```
|
|
853
|
+
*/
|
|
854
|
+
async navigate(sessionId, url) {
|
|
855
|
+
const response = await this.http.request(
|
|
856
|
+
"POST",
|
|
857
|
+
`/v1/sessions/${sessionId}/navigate`,
|
|
858
|
+
{
|
|
859
|
+
json: { url }
|
|
860
|
+
}
|
|
861
|
+
);
|
|
862
|
+
return {
|
|
863
|
+
currentUrl: response.current_url ?? response.currentUrl
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Get a screenshot of the browser
|
|
868
|
+
*
|
|
869
|
+
* @param sessionId - Session UUID
|
|
870
|
+
* @returns ScreenshotResponse with base64-encoded image, URL, and title
|
|
871
|
+
*
|
|
872
|
+
* @example
|
|
873
|
+
* ```typescript
|
|
874
|
+
* const screenshot = await client.sessions.screenshot('session-uuid');
|
|
875
|
+
* console.log(screenshot.url);
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
async screenshot(sessionId) {
|
|
879
|
+
return this.http.request("GET", `/v1/sessions/${sessionId}/screenshot`);
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
// src/client.ts
|
|
884
|
+
var AGIClient = class {
|
|
885
|
+
http;
|
|
886
|
+
/** Sessions resource for low-level API access */
|
|
887
|
+
sessions;
|
|
888
|
+
/**
|
|
889
|
+
* Create a new AGI client
|
|
890
|
+
*
|
|
891
|
+
* @param options - Client configuration options
|
|
892
|
+
*
|
|
893
|
+
* @example
|
|
894
|
+
* ```typescript
|
|
895
|
+
* // With explicit API key
|
|
896
|
+
* const client = new AGIClient({ apiKey: 'your_api_key' });
|
|
897
|
+
*
|
|
898
|
+
* // With custom base URL
|
|
899
|
+
* const client = new AGIClient({
|
|
900
|
+
* apiKey: 'your_api_key',
|
|
901
|
+
* baseUrl: 'https://custom-api.example.com',
|
|
902
|
+
* timeout: 120000,
|
|
903
|
+
* });
|
|
904
|
+
* ```
|
|
905
|
+
*/
|
|
906
|
+
constructor(options) {
|
|
907
|
+
if (!options.apiKey) {
|
|
908
|
+
throw new Error(
|
|
909
|
+
"api_key is required. Either pass it as a parameter or set the AGI_API_KEY environment variable."
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
this.http = new HTTPClient(options);
|
|
913
|
+
this.sessions = new SessionsResource(this.http);
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Create a session context manager for easy session lifecycle management (recommended)
|
|
917
|
+
*
|
|
918
|
+
* This is the recommended way to use the SDK. The context manager automatically
|
|
919
|
+
* creates and deletes the session using `await using` syntax.
|
|
920
|
+
*
|
|
921
|
+
* @param agentName - Agent model to use (e.g., "agi-0", "agi-0-fast", "agi-1")
|
|
922
|
+
* @param options - Session creation options
|
|
923
|
+
* @returns SessionContext manager
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```typescript
|
|
927
|
+
* // Simple usage
|
|
928
|
+
* await using session = client.session('agi-0');
|
|
929
|
+
* const result = await session.runTask('Find flights SFO→JFK under $450');
|
|
930
|
+
* console.log(result.data);
|
|
931
|
+
* // Session automatically deleted
|
|
932
|
+
*
|
|
933
|
+
* // With options
|
|
934
|
+
* await using session = client.session('agi-0', {
|
|
935
|
+
* webhookUrl: 'https://yourapp.com/webhook',
|
|
936
|
+
* maxSteps: 200
|
|
937
|
+
* });
|
|
938
|
+
* const result = await session.runTask('Research company XYZ');
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
session(agentName = "agi-0", options) {
|
|
942
|
+
return new SessionContext(this, agentName, options);
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
|
|
946
|
+
exports.AGIClient = AGIClient;
|
|
947
|
+
exports.AGIError = AGIError;
|
|
948
|
+
exports.APIError = APIError;
|
|
949
|
+
exports.AgentExecutionError = AgentExecutionError;
|
|
950
|
+
exports.AuthenticationError = AuthenticationError;
|
|
951
|
+
exports.NotFoundError = NotFoundError;
|
|
952
|
+
exports.PermissionError = PermissionError;
|
|
953
|
+
exports.RateLimitError = RateLimitError;
|
|
954
|
+
exports.Screenshot = Screenshot;
|
|
955
|
+
exports.SessionContext = SessionContext;
|
|
956
|
+
exports.SessionsResource = SessionsResource;
|
|
957
|
+
exports.ValidationError = ValidationError;
|
|
958
|
+
//# sourceMappingURL=index.js.map
|
|
959
|
+
//# sourceMappingURL=index.js.map
|