@marktoflow/integrations 2.0.3 → 2.0.4

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.
Files changed (55) hide show
  1. package/README.md +65 -16
  2. package/dist/adapters/claude-agent-types.d.ts +28 -28
  3. package/dist/adapters/claude-agent-workflow.d.ts +16 -16
  4. package/dist/adapters/codex-types.d.ts +6 -6
  5. package/dist/adapters/codex-workflow.d.ts +16 -16
  6. package/dist/adapters/github-copilot-types.d.ts +22 -22
  7. package/dist/adapters/github-copilot-workflow.d.ts +14 -14
  8. package/dist/adapters/ollama-types.d.ts +42 -42
  9. package/dist/adapters/openai-types.d.ts +552 -33
  10. package/dist/adapters/openai-types.d.ts.map +1 -1
  11. package/dist/adapters/openai-types.js +58 -5
  12. package/dist/adapters/openai-types.js.map +1 -1
  13. package/dist/adapters/openai.d.ts +59 -5
  14. package/dist/adapters/openai.d.ts.map +1 -1
  15. package/dist/adapters/openai.js +211 -32
  16. package/dist/adapters/openai.js.map +1 -1
  17. package/dist/services/playwright/client.d.ts +110 -0
  18. package/dist/services/playwright/client.d.ts.map +1 -0
  19. package/dist/services/playwright/client.js +690 -0
  20. package/dist/services/playwright/client.js.map +1 -0
  21. package/dist/services/playwright/index.d.ts +7 -0
  22. package/dist/services/playwright/index.d.ts.map +1 -0
  23. package/dist/services/playwright/index.js +7 -0
  24. package/dist/services/playwright/index.js.map +1 -0
  25. package/dist/services/playwright/initializer.d.ts +24 -0
  26. package/dist/services/playwright/initializer.d.ts.map +1 -0
  27. package/dist/services/playwright/initializer.js +99 -0
  28. package/dist/services/playwright/initializer.js.map +1 -0
  29. package/dist/services/playwright/types.d.ts +270 -0
  30. package/dist/services/playwright/types.d.ts.map +1 -0
  31. package/dist/services/playwright/types.js +5 -0
  32. package/dist/services/playwright/types.js.map +1 -0
  33. package/dist/services/playwright.d.ts +3 -675
  34. package/dist/services/playwright.d.ts.map +1 -1
  35. package/dist/services/playwright.js +3 -1138
  36. package/dist/services/playwright.js.map +1 -1
  37. package/package.json +25 -7
  38. package/dist/adapters/claude-agent-hooks.d.ts +0 -176
  39. package/dist/services/github.d.ts +0 -3
  40. package/dist/services/gmail-trigger.d.ts +0 -92
  41. package/dist/services/gmail.d.ts +0 -116
  42. package/dist/services/google-calendar.d.ts +0 -220
  43. package/dist/services/google-docs.d.ts +0 -197
  44. package/dist/services/google-drive.d.ts +0 -149
  45. package/dist/services/google-sheets.d.ts +0 -165
  46. package/dist/services/http.d.ts +0 -120
  47. package/dist/services/jira.d.ts +0 -3
  48. package/dist/services/linear.d.ts +0 -163
  49. package/dist/services/mysql.d.ts +0 -91
  50. package/dist/services/outlook-trigger.d.ts +0 -121
  51. package/dist/services/outlook.d.ts +0 -237
  52. package/dist/services/postgres.d.ts +0 -83
  53. package/dist/services/slack-socket.d.ts +0 -18
  54. package/dist/services/slack.d.ts +0 -3
  55. package/dist/services/whatsapp.d.ts +0 -311
@@ -0,0 +1,690 @@
1
+ /**
2
+ * PlaywrightClient — Core browser automation methods.
3
+ */
4
+ export class PlaywrightClient {
5
+ playwright = null;
6
+ browser = null;
7
+ context = null;
8
+ page = null;
9
+ config;
10
+ stagehand = null;
11
+ aiBrowser = null;
12
+ sessionPath = null;
13
+ constructor(config = {}) {
14
+ this.config = {
15
+ browserType: 'chromium',
16
+ headless: true,
17
+ timeout: 30000,
18
+ viewport: { width: 1280, height: 720 },
19
+ sessionsDir: './sessions',
20
+ autoSaveSession: false,
21
+ ...config,
22
+ };
23
+ }
24
+ getSessionPath(sessionId) {
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+ const sessionsDir = this.config.sessionsDir || './sessions';
28
+ if (!fs.existsSync(sessionsDir)) {
29
+ fs.mkdirSync(sessionsDir, { recursive: true });
30
+ }
31
+ return path.join(sessionsDir, `${sessionId}.json`);
32
+ }
33
+ async launch() {
34
+ if (this.browser)
35
+ return;
36
+ this.playwright = await import('playwright');
37
+ const browserType = this.config.browserType || 'chromium';
38
+ const launchOptions = {
39
+ headless: this.config.headless,
40
+ slowMo: this.config.slowMo,
41
+ timeout: this.config.timeout,
42
+ };
43
+ if (this.config.proxy) {
44
+ launchOptions.proxy = this.config.proxy;
45
+ }
46
+ if (this.config.wsEndpoint) {
47
+ this.browser = await this.playwright[browserType].connect(this.config.wsEndpoint);
48
+ }
49
+ else {
50
+ this.browser = await this.playwright[browserType].launch(launchOptions);
51
+ }
52
+ const contextOptions = {
53
+ viewport: this.config.viewport,
54
+ userAgent: this.config.userAgent,
55
+ locale: this.config.locale,
56
+ timezoneId: this.config.timezoneId,
57
+ geolocation: this.config.geolocation,
58
+ permissions: this.config.permissions,
59
+ ignoreHTTPSErrors: this.config.ignoreHTTPSErrors,
60
+ extraHTTPHeaders: this.config.extraHTTPHeaders,
61
+ recordVideo: this.config.recordVideo,
62
+ };
63
+ if (this.config.sessionId) {
64
+ const sessionPath = this.getSessionPath(this.config.sessionId);
65
+ const fs = require('fs');
66
+ if (fs.existsSync(sessionPath)) {
67
+ contextOptions.storageState = sessionPath;
68
+ this.sessionPath = sessionPath;
69
+ }
70
+ }
71
+ else if (this.config.storageState) {
72
+ contextOptions.storageState = this.config.storageState;
73
+ this.sessionPath = this.config.storageState;
74
+ }
75
+ if (this.config.deviceName && this.playwright.devices[this.config.deviceName]) {
76
+ Object.assign(contextOptions, this.playwright.devices[this.config.deviceName]);
77
+ }
78
+ this.context = await this.browser.newContext(contextOptions);
79
+ this.page = await this.context.newPage();
80
+ }
81
+ async ensureLaunched() {
82
+ if (!this.page)
83
+ await this.launch();
84
+ return this.page;
85
+ }
86
+ async navigate(options) {
87
+ const page = await this.ensureLaunched();
88
+ await page.goto(options.url, {
89
+ waitUntil: options.waitUntil || 'load',
90
+ timeout: options.timeout,
91
+ referer: options.referer,
92
+ });
93
+ return { url: page.url(), title: await page.title() };
94
+ }
95
+ async click(options) {
96
+ const page = await this.ensureLaunched();
97
+ await page.click(options.selector, {
98
+ button: options.button,
99
+ clickCount: options.clickCount,
100
+ delay: options.delay,
101
+ modifiers: options.modifiers,
102
+ position: options.position,
103
+ force: options.force,
104
+ timeout: options.timeout,
105
+ });
106
+ }
107
+ async dblclick(options) {
108
+ const page = await this.ensureLaunched();
109
+ await page.dblclick(options.selector, {
110
+ button: options.button,
111
+ delay: options.delay,
112
+ modifiers: options.modifiers,
113
+ position: options.position,
114
+ force: options.force,
115
+ timeout: options.timeout,
116
+ });
117
+ }
118
+ async type(options) {
119
+ const page = await this.ensureLaunched();
120
+ if (options.clear)
121
+ await page.fill(options.selector, '');
122
+ await page.type(options.selector, options.text, {
123
+ delay: options.delay,
124
+ timeout: options.timeout,
125
+ });
126
+ }
127
+ async fill(options) {
128
+ const page = await this.ensureLaunched();
129
+ await page.fill(options.selector, options.value, {
130
+ force: options.force,
131
+ timeout: options.timeout,
132
+ });
133
+ }
134
+ async select(options) {
135
+ const page = await this.ensureLaunched();
136
+ const values = Array.isArray(options.values) ? options.values : [options.values];
137
+ return page.selectOption(options.selector, values, { timeout: options.timeout });
138
+ }
139
+ async check(selector, options) {
140
+ const page = await this.ensureLaunched();
141
+ await page.check(selector, options);
142
+ }
143
+ async uncheck(selector, options) {
144
+ const page = await this.ensureLaunched();
145
+ await page.uncheck(selector, options);
146
+ }
147
+ async hover(selector, options) {
148
+ const page = await this.ensureLaunched();
149
+ await page.hover(selector, options);
150
+ }
151
+ async focus(selector, options) {
152
+ const page = await this.ensureLaunched();
153
+ await page.focus(selector, options);
154
+ }
155
+ async press(selector, key, options) {
156
+ const page = await this.ensureLaunched();
157
+ await page.press(selector, key, options);
158
+ }
159
+ async keyboard(key, options) {
160
+ const page = await this.ensureLaunched();
161
+ await page.keyboard.press(key, options);
162
+ }
163
+ async screenshot(options = {}) {
164
+ const page = await this.ensureLaunched();
165
+ let element = null;
166
+ if (options.selector) {
167
+ element = await page.$(options.selector);
168
+ if (!element)
169
+ throw new Error(`Element not found: ${options.selector}`);
170
+ }
171
+ const screenshotOptions = {
172
+ path: options.path,
173
+ type: options.type || 'png',
174
+ quality: options.type === 'jpeg' ? options.quality : undefined,
175
+ fullPage: options.fullPage,
176
+ clip: options.clip,
177
+ omitBackground: options.omitBackground,
178
+ };
179
+ const buffer = element
180
+ ? await element.screenshot(screenshotOptions)
181
+ : await page.screenshot(screenshotOptions);
182
+ return { data: buffer.toString('base64'), path: options.path, type: options.type || 'png' };
183
+ }
184
+ async pdf(options = {}) {
185
+ const page = await this.ensureLaunched();
186
+ const buffer = await page.pdf({
187
+ path: options.path,
188
+ format: options.format,
189
+ scale: options.scale,
190
+ displayHeaderFooter: options.displayHeaderFooter,
191
+ headerTemplate: options.headerTemplate,
192
+ footerTemplate: options.footerTemplate,
193
+ printBackground: options.printBackground,
194
+ landscape: options.landscape,
195
+ pageRanges: options.pageRanges,
196
+ width: options.width,
197
+ height: options.height,
198
+ margin: options.margin,
199
+ });
200
+ return { data: buffer.toString('base64'), path: options.path };
201
+ }
202
+ async evaluate(options) {
203
+ const page = await this.ensureLaunched();
204
+ if (options.expression.trim().startsWith('(') || options.expression.trim().startsWith('function')) {
205
+ return page.evaluate(options.expression, options.args);
206
+ }
207
+ else {
208
+ const wrappedExpression = `() => (${options.expression})`;
209
+ return page.evaluate(wrappedExpression);
210
+ }
211
+ }
212
+ async wait(options) {
213
+ const page = await this.ensureLaunched();
214
+ if (options.selector) {
215
+ await page.waitForSelector(options.selector, { state: options.state, timeout: options.timeout });
216
+ }
217
+ else if (options.url) {
218
+ await page.waitForURL(options.url, { timeout: options.timeout });
219
+ }
220
+ else if (options.function) {
221
+ const wrappedFn = `() => (${options.function})`;
222
+ await page.waitForFunction(wrappedFn, { timeout: options.timeout });
223
+ }
224
+ else if (options.loadState) {
225
+ await page.waitForLoadState(options.loadState, { timeout: options.timeout });
226
+ }
227
+ else if (options.networkIdle) {
228
+ await page.waitForLoadState('networkidle', { timeout: options.timeout });
229
+ }
230
+ else if (options.timeout) {
231
+ await page.waitForTimeout(options.timeout);
232
+ }
233
+ }
234
+ async extract(options) {
235
+ const page = await this.ensureLaunched();
236
+ const elements = await page.$$(options.selector);
237
+ if (elements.length === 0) {
238
+ return { data: options.all ? [] : null, count: 0 };
239
+ }
240
+ const extractElement = async (el) => {
241
+ const result = {};
242
+ if (options.text)
243
+ result.text = await el.textContent();
244
+ if (options.html)
245
+ result.html = await el.innerHTML();
246
+ if (options.attributes) {
247
+ for (const attr of options.attributes)
248
+ result[attr] = await el.getAttribute(attr);
249
+ }
250
+ if (options.properties) {
251
+ for (const prop of options.properties) {
252
+ result[prop] = await el.evaluate((e, p) => e[p], prop);
253
+ }
254
+ }
255
+ const keys = Object.keys(result);
256
+ if (keys.length === 1)
257
+ return result[keys[0]];
258
+ return result;
259
+ };
260
+ if (options.all) {
261
+ const data = await Promise.all(elements.map(extractElement));
262
+ return { data, count: elements.length };
263
+ }
264
+ else {
265
+ const data = await extractElement(elements[0]);
266
+ return { data, count: 1 };
267
+ }
268
+ }
269
+ async fillForm(options) {
270
+ const page = await this.ensureLaunched();
271
+ const formSelector = options.formSelector || 'form';
272
+ for (const [name, value] of Object.entries(options.fields)) {
273
+ const selector = `${formSelector} [name="${name}"]`;
274
+ if (typeof value === 'boolean') {
275
+ if (value)
276
+ await page.check(selector);
277
+ else
278
+ await page.uncheck(selector);
279
+ }
280
+ else if (Array.isArray(value)) {
281
+ await page.selectOption(selector, value);
282
+ }
283
+ else {
284
+ await page.fill(selector, value);
285
+ }
286
+ }
287
+ if (options.submit)
288
+ await page.click(`${formSelector} [type="submit"]`);
289
+ }
290
+ async cookies(options = {}) {
291
+ if (!this.context)
292
+ await this.ensureLaunched();
293
+ if (options.cookies)
294
+ await this.context.addCookies(options.cookies);
295
+ return this.context.cookies(options.urls);
296
+ }
297
+ async clearCookies() {
298
+ if (this.context)
299
+ await this.context.clearCookies();
300
+ }
301
+ async storage(options) {
302
+ const page = await this.ensureLaunched();
303
+ const result = {};
304
+ if (options.localStorage) {
305
+ await page.evaluate((items) => {
306
+ for (const [key, value] of Object.entries(items))
307
+ localStorage.setItem(key, value);
308
+ }, options.localStorage);
309
+ }
310
+ if (options.sessionStorage) {
311
+ await page.evaluate((items) => {
312
+ for (const [key, value] of Object.entries(items))
313
+ sessionStorage.setItem(key, value);
314
+ }, options.sessionStorage);
315
+ }
316
+ if (options.getStorage === 'local' || options.getStorage === 'both') {
317
+ result.localStorage = await page.evaluate(() => {
318
+ const items = {};
319
+ for (let i = 0; i < localStorage.length; i++) {
320
+ const key = localStorage.key(i);
321
+ if (key)
322
+ items[key] = localStorage.getItem(key) || '';
323
+ }
324
+ return items;
325
+ });
326
+ }
327
+ if (options.getStorage === 'session' || options.getStorage === 'both') {
328
+ result.sessionStorage = await page.evaluate(() => {
329
+ const items = {};
330
+ for (let i = 0; i < sessionStorage.length; i++) {
331
+ const key = sessionStorage.key(i);
332
+ if (key)
333
+ items[key] = sessionStorage.getItem(key) || '';
334
+ }
335
+ return items;
336
+ });
337
+ }
338
+ return result;
339
+ }
340
+ async blockRequests(patterns) {
341
+ const page = await this.ensureLaunched();
342
+ await page.route((url) => patterns.some((p) => url.href.includes(p)), (route) => route.abort());
343
+ }
344
+ async interceptRequests(handler) {
345
+ const page = await this.ensureLaunched();
346
+ await page.route('**/*', handler);
347
+ }
348
+ async content() {
349
+ const page = await this.ensureLaunched();
350
+ return page.content();
351
+ }
352
+ async pageInfo(includeContent = false) {
353
+ const page = await this.ensureLaunched();
354
+ return {
355
+ url: page.url(),
356
+ title: await page.title(),
357
+ content: includeContent ? await page.content() : undefined,
358
+ };
359
+ }
360
+ async goBack(options) {
361
+ const page = await this.ensureLaunched();
362
+ await page.goBack(options);
363
+ }
364
+ async goForward(options) {
365
+ const page = await this.ensureLaunched();
366
+ await page.goForward(options);
367
+ }
368
+ async reload(options) {
369
+ const page = await this.ensureLaunched();
370
+ await page.reload(options);
371
+ }
372
+ async newPage() {
373
+ if (!this.context)
374
+ await this.ensureLaunched();
375
+ this.page = await this.context.newPage();
376
+ }
377
+ async getPages() {
378
+ if (!this.context)
379
+ return [];
380
+ const pages = this.context.pages();
381
+ return Promise.all(pages.map(async (p) => ({ url: p.url(), title: await p.title() })));
382
+ }
383
+ async switchToPage(indexOrUrl) {
384
+ if (!this.context)
385
+ throw new Error('No browser context');
386
+ const pages = this.context.pages();
387
+ let targetPage;
388
+ if (typeof indexOrUrl === 'number') {
389
+ targetPage = pages[indexOrUrl];
390
+ }
391
+ else {
392
+ targetPage = pages.find((p) => p.url().includes(indexOrUrl));
393
+ }
394
+ if (!targetPage)
395
+ throw new Error(`Page not found: ${indexOrUrl}`);
396
+ this.page = targetPage;
397
+ return { url: this.page.url(), title: await this.page.title() };
398
+ }
399
+ async closePage() {
400
+ if (this.page) {
401
+ await this.page.close();
402
+ const pages = this.context?.pages() || [];
403
+ this.page = pages.length > 0 ? pages[pages.length - 1] : null;
404
+ }
405
+ }
406
+ async uploadFile(selector, files) {
407
+ const page = await this.ensureLaunched();
408
+ await page.setInputFiles(selector, files);
409
+ }
410
+ async download(options) {
411
+ const page = await this.ensureLaunched();
412
+ const downloadPromise = page.waitForEvent('download');
413
+ if (options.selector)
414
+ await page.click(options.selector);
415
+ else if (options.url)
416
+ await page.goto(options.url);
417
+ const download = await downloadPromise;
418
+ const path = options.path || (await download.path());
419
+ if (options.path)
420
+ await download.saveAs(options.path);
421
+ return { path: path || '', suggestedFilename: download.suggestedFilename() };
422
+ }
423
+ async handleDialog(action, promptText) {
424
+ const page = await this.ensureLaunched();
425
+ page.once('dialog', async (dialog) => {
426
+ if (action === 'accept')
427
+ await dialog.accept(promptText);
428
+ else
429
+ await dialog.dismiss();
430
+ });
431
+ }
432
+ async emulateMedia(options) {
433
+ const page = await this.ensureLaunched();
434
+ await page.emulateMedia(options);
435
+ }
436
+ async close() {
437
+ if (this.config.autoSaveSession && this.config.sessionId && this.context) {
438
+ await this.saveSession().catch(() => { });
439
+ }
440
+ if (this.page) {
441
+ await this.page.close().catch(() => { });
442
+ this.page = null;
443
+ }
444
+ if (this.context) {
445
+ await this.context.close().catch(() => { });
446
+ this.context = null;
447
+ }
448
+ if (this.browser) {
449
+ await this.browser.close().catch(() => { });
450
+ this.browser = null;
451
+ }
452
+ this.stagehand = null;
453
+ }
454
+ getPage() { return this.page; }
455
+ getBrowser() { return this.browser; }
456
+ getContext() { return this.context; }
457
+ // ==========================================================================
458
+ // Session Management
459
+ // ==========================================================================
460
+ async saveSession(sessionIdOrPath) {
461
+ if (!this.context)
462
+ throw new Error('No browser context to save session from');
463
+ let savePath;
464
+ if (sessionIdOrPath) {
465
+ if (sessionIdOrPath.includes('/') || sessionIdOrPath.includes('\\') || sessionIdOrPath.endsWith('.json')) {
466
+ savePath = sessionIdOrPath;
467
+ }
468
+ else {
469
+ savePath = this.getSessionPath(sessionIdOrPath);
470
+ }
471
+ }
472
+ else if (this.config.sessionId) {
473
+ savePath = this.getSessionPath(this.config.sessionId);
474
+ }
475
+ else if (this.sessionPath) {
476
+ savePath = this.sessionPath;
477
+ }
478
+ else {
479
+ throw new Error('No session ID or path specified');
480
+ }
481
+ await this.context.storageState({ path: savePath });
482
+ this.sessionPath = savePath;
483
+ const cookies = await this.context.cookies();
484
+ const domains = [...new Set(cookies.map(c => c.domain))];
485
+ const sessionId = savePath.split('/').pop()?.replace('.json', '') || 'unknown';
486
+ const now = new Date().toISOString();
487
+ return { id: sessionId, path: savePath, createdAt: now, lastUsedAt: now, domains };
488
+ }
489
+ async loadSession(sessionIdOrPath) {
490
+ const fs = require('fs');
491
+ let loadPath;
492
+ if (sessionIdOrPath.includes('/') || sessionIdOrPath.includes('\\') || sessionIdOrPath.endsWith('.json')) {
493
+ loadPath = sessionIdOrPath;
494
+ }
495
+ else {
496
+ loadPath = this.getSessionPath(sessionIdOrPath);
497
+ }
498
+ if (!fs.existsSync(loadPath))
499
+ throw new Error(`Session file not found: ${loadPath}`);
500
+ if (this.browser) {
501
+ if (this.context)
502
+ await this.context.close();
503
+ const contextOptions = {
504
+ viewport: this.config.viewport,
505
+ userAgent: this.config.userAgent,
506
+ locale: this.config.locale,
507
+ timezoneId: this.config.timezoneId,
508
+ storageState: loadPath,
509
+ };
510
+ this.context = await this.browser.newContext(contextOptions);
511
+ this.page = await this.context.newPage();
512
+ }
513
+ else {
514
+ this.config.storageState = loadPath;
515
+ }
516
+ this.sessionPath = loadPath;
517
+ const sessionData = JSON.parse(fs.readFileSync(loadPath, 'utf-8'));
518
+ const domains = [...new Set((sessionData.cookies || []).map((c) => c.domain))];
519
+ const sessionId = loadPath.split('/').pop()?.replace('.json', '') || 'unknown';
520
+ return { id: sessionId, path: loadPath, createdAt: new Date().toISOString(), lastUsedAt: new Date().toISOString(), domains: domains };
521
+ }
522
+ async listSessions() {
523
+ const fs = require('fs');
524
+ const path = require('path');
525
+ const sessionsDir = this.config.sessionsDir || './sessions';
526
+ if (!fs.existsSync(sessionsDir))
527
+ return [];
528
+ const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));
529
+ const sessions = [];
530
+ for (const file of files) {
531
+ const filePath = path.join(sessionsDir, file);
532
+ try {
533
+ const stat = fs.statSync(filePath);
534
+ const sessionData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
535
+ const domains = [...new Set((sessionData.cookies || []).map((c) => c.domain))];
536
+ sessions.push({
537
+ id: file.replace('.json', ''),
538
+ path: filePath,
539
+ createdAt: stat.birthtime.toISOString(),
540
+ lastUsedAt: stat.mtime.toISOString(),
541
+ domains: domains,
542
+ });
543
+ }
544
+ catch { /* Skip invalid files */ }
545
+ }
546
+ return sessions;
547
+ }
548
+ async deleteSession(sessionId) {
549
+ const fs = require('fs');
550
+ const sessionPath = this.getSessionPath(sessionId);
551
+ if (fs.existsSync(sessionPath)) {
552
+ fs.unlinkSync(sessionPath);
553
+ return true;
554
+ }
555
+ return false;
556
+ }
557
+ hasSession(sessionId) {
558
+ const fs = require('fs');
559
+ return fs.existsSync(this.getSessionPath(sessionId));
560
+ }
561
+ // ==========================================================================
562
+ // AI-Powered Automation
563
+ // ==========================================================================
564
+ async initAIBrowser() {
565
+ if (this.aiBrowser)
566
+ return this.aiBrowser;
567
+ if (!this.config.enableAI)
568
+ throw new Error('AI automation is not enabled. Set enableAI: true in config.');
569
+ if (!this.config.aiBackend || this.config.aiBackend === 'stagehand') {
570
+ throw new Error('Custom AI backend not configured. Set aiBackend to "copilot" or "openai"');
571
+ }
572
+ if (!this.config.aiClient)
573
+ throw new Error(`AI client not provided. Initialize ${this.config.aiBackend} client first.`);
574
+ try {
575
+ const { AIBrowserClient } = await import('../ai-browser.js');
576
+ this.aiBrowser = new AIBrowserClient({
577
+ backend: this.config.aiBackend,
578
+ aiClient: this.config.aiClient,
579
+ playwrightClient: this,
580
+ debug: this.config.aiDebug,
581
+ });
582
+ return this.aiBrowser;
583
+ }
584
+ catch (error) {
585
+ throw new Error(`Failed to initialize AI browser automation: ${error instanceof Error ? error.message : String(error)}`);
586
+ }
587
+ }
588
+ async initStagehand() {
589
+ if (this.stagehand)
590
+ return this.stagehand;
591
+ if (!this.config.enableAI)
592
+ throw new Error('AI automation is not enabled. Set enableAI: true in config.');
593
+ try {
594
+ const stagehandPackage = '@browserbasehq/stagehand';
595
+ let stagehandModule = null;
596
+ try {
597
+ stagehandModule = await import(stagehandPackage);
598
+ }
599
+ catch {
600
+ throw new Error('Stagehand is not installed. Install it with: npm install @browserbasehq/stagehand');
601
+ }
602
+ const { Stagehand } = stagehandModule;
603
+ await this.ensureLaunched();
604
+ const stagehandConfig = {
605
+ env: 'LOCAL',
606
+ enableCaching: true,
607
+ debugDom: this.config.aiDebug,
608
+ };
609
+ if (this.config.aiProvider === 'anthropic') {
610
+ stagehandConfig.modelName = this.config.aiModel || 'claude-3-5-sonnet-latest';
611
+ stagehandConfig.modelClientOptions = { apiKey: this.config.aiApiKey || process.env.ANTHROPIC_API_KEY };
612
+ }
613
+ else {
614
+ stagehandConfig.modelName = this.config.aiModel || 'gpt-4o';
615
+ stagehandConfig.modelClientOptions = { apiKey: this.config.aiApiKey || process.env.OPENAI_API_KEY };
616
+ }
617
+ this.stagehand = new Stagehand(stagehandConfig);
618
+ await this.stagehand.init({ page: this.page });
619
+ return this.stagehand;
620
+ }
621
+ catch (error) {
622
+ throw new Error(`Failed to initialize Stagehand AI. Make sure @browserbasehq/stagehand is installed: npm install @browserbasehq/stagehand\nOriginal error: ${error}`);
623
+ }
624
+ }
625
+ async act(options) {
626
+ if (this.config.aiBackend && this.config.aiBackend !== 'stagehand') {
627
+ const aiBrowser = await this.initAIBrowser();
628
+ try {
629
+ const result = await aiBrowser.act({ action: options.instruction });
630
+ return { success: result.success, action: result.action, element: result.message };
631
+ }
632
+ catch (error) {
633
+ if (options.optional)
634
+ return { success: false, error: String(error) };
635
+ throw error;
636
+ }
637
+ }
638
+ const stagehand = await this.initStagehand();
639
+ try {
640
+ const result = await stagehand.act({ action: options.instruction });
641
+ return { success: result.success !== false, action: result.action || options.instruction, element: result.message };
642
+ }
643
+ catch (error) {
644
+ if (options.optional)
645
+ return { success: false, error: String(error) };
646
+ throw error;
647
+ }
648
+ }
649
+ async observe(options = {}) {
650
+ if (this.config.aiBackend && this.config.aiBackend !== 'stagehand') {
651
+ const aiBrowser = await this.initAIBrowser();
652
+ const elements = await aiBrowser.observe({ instruction: options.instruction });
653
+ return {
654
+ elements: elements.map(el => ({
655
+ description: el.description || '',
656
+ selector: el.selector || '',
657
+ tagName: el.tagName || 'unknown',
658
+ text: el.text,
659
+ actions: el.actions || ['click'],
660
+ })),
661
+ };
662
+ }
663
+ const stagehand = await this.initStagehand();
664
+ const result = await stagehand.observe({ instruction: options.instruction });
665
+ return {
666
+ elements: (result || []).map(el => ({
667
+ description: el.description || '',
668
+ selector: el.selector || '',
669
+ tagName: el.tagName || 'unknown',
670
+ actions: el.actions || ['click'],
671
+ })),
672
+ };
673
+ }
674
+ async aiExtract(options) {
675
+ if (this.config.aiBackend && this.config.aiBackend !== 'stagehand') {
676
+ const aiBrowser = await this.initAIBrowser();
677
+ const result = await aiBrowser.aiExtract({ instruction: options.instruction, schema: options.schema });
678
+ return result.data;
679
+ }
680
+ const stagehand = await this.initStagehand();
681
+ let schema = undefined;
682
+ if (options.schema)
683
+ schema = options.schema;
684
+ return stagehand.extract({ instruction: options.instruction, schema });
685
+ }
686
+ isAIEnabled() {
687
+ return this.config.enableAI === true;
688
+ }
689
+ }
690
+ //# sourceMappingURL=client.js.map