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/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