@yourgpt/copilot-sdk 0.1.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.
@@ -0,0 +1,1915 @@
1
+ 'use strict';
2
+
3
+ // src/core/tools/screenshot.ts
4
+ var isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
5
+ var DEFAULT_OPTIONS = {
6
+ element: isBrowser ? document.body : null,
7
+ quality: 0.8,
8
+ format: "png",
9
+ maxWidth: 1920,
10
+ maxHeight: 1080,
11
+ includeCursor: false
12
+ };
13
+ var html2canvasPromise = null;
14
+ async function getHtml2Canvas() {
15
+ if (!html2canvasPromise) {
16
+ html2canvasPromise = import('html2canvas').then((mod) => mod.default);
17
+ }
18
+ return html2canvasPromise;
19
+ }
20
+ async function captureScreenshot(options = {}) {
21
+ if (!isBrowser) {
22
+ throw new Error(
23
+ "Screenshot capture is only available in browser environment"
24
+ );
25
+ }
26
+ const opts = { ...DEFAULT_OPTIONS, ...options };
27
+ const element = opts.element || document.body;
28
+ const rect = element.getBoundingClientRect();
29
+ let width = rect.width || window.innerWidth;
30
+ let height = rect.height || window.innerHeight;
31
+ const scale = Math.min(opts.maxWidth / width, opts.maxHeight / height, 1);
32
+ width = Math.round(width * scale);
33
+ height = Math.round(height * scale);
34
+ let canvas;
35
+ try {
36
+ const html2canvas = await getHtml2Canvas();
37
+ canvas = await html2canvas(element, {
38
+ scale,
39
+ useCORS: true,
40
+ // Enable cross-origin images
41
+ allowTaint: false,
42
+ // Don't allow tainted canvas
43
+ backgroundColor: null,
44
+ // Transparent background (uses element's bg)
45
+ logging: false,
46
+ // Disable internal logging
47
+ width: rect.width,
48
+ height: rect.height,
49
+ windowWidth: window.innerWidth,
50
+ windowHeight: window.innerHeight,
51
+ scrollX: 0,
52
+ scrollY: 0,
53
+ x: rect.left + window.scrollX,
54
+ y: rect.top + window.scrollY
55
+ });
56
+ } catch (error) {
57
+ canvas = document.createElement("canvas");
58
+ canvas.width = width;
59
+ canvas.height = height;
60
+ const ctx = canvas.getContext("2d");
61
+ if (ctx) {
62
+ createPlaceholder(ctx, width, height, element, String(error));
63
+ }
64
+ }
65
+ const mimeType = `image/${opts.format === "jpeg" ? "jpeg" : opts.format}`;
66
+ let data;
67
+ try {
68
+ data = canvas.toDataURL(mimeType, opts.quality);
69
+ } catch (e) {
70
+ if (e instanceof DOMException && e.name === "SecurityError") {
71
+ console.warn(
72
+ "[Copilot SDK] Canvas tainted by cross-origin content. Creating placeholder."
73
+ );
74
+ const cleanCanvas = document.createElement("canvas");
75
+ cleanCanvas.width = width;
76
+ cleanCanvas.height = height;
77
+ const cleanCtx = cleanCanvas.getContext("2d");
78
+ if (cleanCtx) {
79
+ createPlaceholder(
80
+ cleanCtx,
81
+ width,
82
+ height,
83
+ element,
84
+ "Cross-origin content blocked"
85
+ );
86
+ data = cleanCanvas.toDataURL(mimeType, opts.quality);
87
+ } else {
88
+ throw new Error("Failed to create placeholder canvas");
89
+ }
90
+ } else {
91
+ throw e;
92
+ }
93
+ }
94
+ return {
95
+ data,
96
+ format: opts.format,
97
+ width: canvas.width,
98
+ height: canvas.height,
99
+ timestamp: Date.now()
100
+ };
101
+ }
102
+ function createPlaceholder(ctx, width, height, element, errorMessage) {
103
+ ctx.fillStyle = "#f0f0f0";
104
+ ctx.fillRect(0, 0, width, height);
105
+ ctx.strokeStyle = "#ddd";
106
+ ctx.lineWidth = 2;
107
+ ctx.strokeRect(2, 2, width - 4, height - 4);
108
+ ctx.fillStyle = "#666";
109
+ ctx.font = "14px system-ui, sans-serif";
110
+ ctx.textAlign = "center";
111
+ ctx.textBaseline = "middle";
112
+ const tagName = element.tagName.toLowerCase();
113
+ const id = element.id ? `#${element.id}` : "";
114
+ const className = element.className ? `.${String(element.className).split(" ")[0]}` : "";
115
+ ctx.fillText(
116
+ `Screenshot: <${tagName}${id}${className}>`,
117
+ width / 2,
118
+ height / 2 - 20
119
+ );
120
+ ctx.fillText(
121
+ `${Math.round(width)}\xD7${Math.round(height)}px`,
122
+ width / 2,
123
+ height / 2
124
+ );
125
+ if (errorMessage) {
126
+ ctx.fillStyle = "#999";
127
+ ctx.font = "12px system-ui, sans-serif";
128
+ ctx.fillText(
129
+ `Error: ${errorMessage.slice(0, 50)}`,
130
+ width / 2,
131
+ height / 2 + 20
132
+ );
133
+ }
134
+ }
135
+ function isScreenshotSupported() {
136
+ return isBrowser && typeof document.createElement === "function";
137
+ }
138
+ async function resizeScreenshot(screenshot, maxWidth, maxHeight) {
139
+ if (!isBrowser) {
140
+ throw new Error("Resize is only available in browser environment");
141
+ }
142
+ return new Promise((resolve, reject) => {
143
+ const img = new Image();
144
+ img.onload = () => {
145
+ const scale = Math.min(maxWidth / img.width, maxHeight / img.height, 1);
146
+ const width = Math.round(img.width * scale);
147
+ const height = Math.round(img.height * scale);
148
+ const canvas = document.createElement("canvas");
149
+ canvas.width = width;
150
+ canvas.height = height;
151
+ const ctx = canvas.getContext("2d");
152
+ if (!ctx) {
153
+ reject(new Error("Failed to create canvas context"));
154
+ return;
155
+ }
156
+ ctx.drawImage(img, 0, 0, width, height);
157
+ const data = canvas.toDataURL(`image/${screenshot.format}`, 0.8);
158
+ resolve({
159
+ ...screenshot,
160
+ data,
161
+ width,
162
+ height,
163
+ timestamp: Date.now()
164
+ });
165
+ };
166
+ img.onerror = () => reject(new Error("Failed to load screenshot"));
167
+ img.src = screenshot.data;
168
+ });
169
+ }
170
+
171
+ // src/core/tools/console.ts
172
+ var isBrowser2 = typeof window !== "undefined" && typeof console !== "undefined";
173
+ var capturedLogs = [];
174
+ var isCapturing = false;
175
+ var captureOptions;
176
+ var originalMethods = {
177
+ log: console.log,
178
+ info: console.info,
179
+ warn: console.warn,
180
+ error: console.error,
181
+ debug: console.debug
182
+ };
183
+ var DEFAULT_OPTIONS2 = {
184
+ types: ["log", "info", "warn", "error", "debug"],
185
+ limit: 100,
186
+ filter: () => true
187
+ };
188
+ function argsToMessage(args) {
189
+ return args.map((arg) => {
190
+ if (arg === null) return "null";
191
+ if (arg === void 0) return "undefined";
192
+ if (typeof arg === "string") return arg;
193
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
194
+ try {
195
+ return JSON.stringify(arg, null, 2);
196
+ } catch {
197
+ return String(arg);
198
+ }
199
+ }).join(" ");
200
+ }
201
+ function getStackTrace() {
202
+ try {
203
+ const error = new Error();
204
+ const stack = error.stack?.split("\n").slice(3).join("\n");
205
+ return stack;
206
+ } catch {
207
+ return void 0;
208
+ }
209
+ }
210
+ function createInterceptor(type) {
211
+ return (...args) => {
212
+ originalMethods[type].apply(console, args);
213
+ if (!captureOptions.types.includes(type)) {
214
+ return;
215
+ }
216
+ const entry = {
217
+ type,
218
+ message: argsToMessage(args),
219
+ args: args.length > 1 ? args : void 0,
220
+ timestamp: Date.now()
221
+ };
222
+ if (type === "error" || type === "warn") {
223
+ entry.stack = getStackTrace();
224
+ }
225
+ if (args[0] instanceof Error) {
226
+ entry.stack = args[0].stack;
227
+ }
228
+ if (!captureOptions.filter(entry)) {
229
+ return;
230
+ }
231
+ capturedLogs.push(entry);
232
+ while (capturedLogs.length > captureOptions.limit) {
233
+ capturedLogs.shift();
234
+ }
235
+ };
236
+ }
237
+ function startConsoleCapture(options = {}) {
238
+ if (!isBrowser2) {
239
+ console.warn("Console capture is only available in browser environment");
240
+ return;
241
+ }
242
+ if (isCapturing) {
243
+ console.warn("Console capture already active");
244
+ return;
245
+ }
246
+ captureOptions = { ...DEFAULT_OPTIONS2, ...options };
247
+ isCapturing = true;
248
+ Object.keys(originalMethods).forEach((type) => {
249
+ console[type] = createInterceptor(type);
250
+ });
251
+ }
252
+ function stopConsoleCapture() {
253
+ if (!isCapturing) {
254
+ return;
255
+ }
256
+ isCapturing = false;
257
+ Object.keys(originalMethods).forEach((type) => {
258
+ console[type] = originalMethods[type];
259
+ });
260
+ }
261
+ function getConsoleLogs(options = {}) {
262
+ const opts = { ...DEFAULT_OPTIONS2, ...options };
263
+ let logs = [...capturedLogs];
264
+ if (opts.types.length < Object.keys(originalMethods).length) {
265
+ logs = logs.filter((entry) => opts.types.includes(entry.type));
266
+ }
267
+ if (opts.filter !== DEFAULT_OPTIONS2.filter) {
268
+ logs = logs.filter(opts.filter);
269
+ }
270
+ const totalCaptured = logs.length;
271
+ logs = logs.slice(-opts.limit);
272
+ return {
273
+ logs,
274
+ totalCaptured
275
+ };
276
+ }
277
+ function clearConsoleLogs() {
278
+ capturedLogs = [];
279
+ }
280
+ function isConsoleCaptureActive() {
281
+ return isCapturing;
282
+ }
283
+ function getConsoleErrors(limit = 50) {
284
+ return getConsoleLogs({
285
+ types: ["error"],
286
+ limit
287
+ }).logs;
288
+ }
289
+ function getConsoleWarnings(limit = 50) {
290
+ return getConsoleLogs({
291
+ types: ["warn"],
292
+ limit
293
+ }).logs;
294
+ }
295
+ function formatLogsForAI(logs) {
296
+ if (logs.length === 0) {
297
+ return "No console logs captured.";
298
+ }
299
+ const formatted = logs.map((entry, index) => {
300
+ const time = new Date(entry.timestamp).toISOString();
301
+ const typeIcon = {
302
+ error: "\u274C",
303
+ warn: "\u26A0\uFE0F",
304
+ log: "\u{1F4DD}",
305
+ info: "\u2139\uFE0F",
306
+ debug: "\u{1F50D}"
307
+ }[entry.type];
308
+ let text = `[${index + 1}] ${typeIcon} [${entry.type.toUpperCase()}] ${time}
309
+ `;
310
+ text += ` ${entry.message}`;
311
+ if (entry.stack) {
312
+ const stackLines = entry.stack.split("\n").slice(0, 3);
313
+ text += `
314
+ Stack:
315
+ ${stackLines.map((l) => ` ${l.trim()}`).join("\n")}`;
316
+ }
317
+ return text;
318
+ });
319
+ return `Console Logs (${logs.length} entries):
320
+
321
+ ${formatted.join("\n\n")}`;
322
+ }
323
+ function captureCurrentLogs(options = {}) {
324
+ if (isCapturing) {
325
+ return getConsoleLogs(options);
326
+ }
327
+ return getConsoleLogs(options);
328
+ }
329
+ if (isBrowser2) {
330
+ window.addEventListener("beforeunload", () => {
331
+ stopConsoleCapture();
332
+ });
333
+ }
334
+
335
+ // src/core/tools/network.ts
336
+ var isBrowser3 = typeof window !== "undefined";
337
+ var capturedRequests = [];
338
+ var isCapturing2 = false;
339
+ var captureOptions2;
340
+ var originalFetch = isBrowser3 ? window.fetch.bind(window) : null;
341
+ var originalXHROpen = isBrowser3 ? XMLHttpRequest.prototype.open : null;
342
+ var originalXHRSend = isBrowser3 ? XMLHttpRequest.prototype.send : null;
343
+ var DEFAULT_OPTIONS3 = {
344
+ limit: 50,
345
+ failedOnly: true,
346
+ methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"],
347
+ includeUrls: [],
348
+ excludeUrls: [],
349
+ captureRequestBody: true,
350
+ captureResponseBody: true,
351
+ maxBodySize: 1e4
352
+ // 10KB
353
+ };
354
+ function sanitizeHeaders(headers) {
355
+ const sensitiveHeaders = [
356
+ "authorization",
357
+ "cookie",
358
+ "set-cookie",
359
+ "x-api-key",
360
+ "api-key",
361
+ "x-auth-token"
362
+ ];
363
+ const result = {};
364
+ if (!headers) {
365
+ return result;
366
+ }
367
+ const entries = headers instanceof Headers ? Array.from(headers.entries()) : Object.entries(headers);
368
+ for (const [key, value] of entries) {
369
+ if (sensitiveHeaders.includes(key.toLowerCase())) {
370
+ result[key] = "[REDACTED]";
371
+ } else {
372
+ result[key] = value;
373
+ }
374
+ }
375
+ return result;
376
+ }
377
+ function truncateBody(body, maxSize) {
378
+ if (body === null || body === void 0) {
379
+ return body;
380
+ }
381
+ try {
382
+ const str = typeof body === "string" ? body : JSON.stringify(body);
383
+ if (str.length > maxSize) {
384
+ return `${str.slice(0, maxSize)}... [truncated, total: ${str.length} chars]`;
385
+ }
386
+ return body;
387
+ } catch {
388
+ return "[Unable to serialize body]";
389
+ }
390
+ }
391
+ function matchesPatterns(url, patterns) {
392
+ if (patterns.length === 0) return false;
393
+ return patterns.some((pattern) => pattern.test(url));
394
+ }
395
+ function shouldCapture(url, method, failed) {
396
+ if (captureOptions2.failedOnly && !failed) {
397
+ return false;
398
+ }
399
+ if (!captureOptions2.methods.includes(method)) {
400
+ return false;
401
+ }
402
+ if (matchesPatterns(url, captureOptions2.excludeUrls)) {
403
+ return false;
404
+ }
405
+ if (captureOptions2.includeUrls.length > 0 && !matchesPatterns(url, captureOptions2.includeUrls)) {
406
+ return false;
407
+ }
408
+ return true;
409
+ }
410
+ function addCapturedRequest(entry) {
411
+ capturedRequests.push(entry);
412
+ while (capturedRequests.length > captureOptions2.limit) {
413
+ capturedRequests.shift();
414
+ }
415
+ }
416
+ function createFetchInterceptor() {
417
+ return async function interceptedFetch(input, init) {
418
+ const startTime = Date.now();
419
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
420
+ const method = init?.method?.toUpperCase() || "GET";
421
+ let requestBody;
422
+ if (captureOptions2.captureRequestBody && init?.body) {
423
+ try {
424
+ if (typeof init.body === "string") {
425
+ requestBody = JSON.parse(init.body);
426
+ } else {
427
+ requestBody = init.body;
428
+ }
429
+ } catch {
430
+ requestBody = init.body;
431
+ }
432
+ }
433
+ try {
434
+ const response = await originalFetch(input, init);
435
+ const duration = Date.now() - startTime;
436
+ const failed = !response.ok;
437
+ if (shouldCapture(url, method, failed)) {
438
+ let responseBody;
439
+ if (captureOptions2.captureResponseBody && failed) {
440
+ try {
441
+ const clone = response.clone();
442
+ const text = await clone.text();
443
+ try {
444
+ responseBody = JSON.parse(text);
445
+ } catch {
446
+ responseBody = text;
447
+ }
448
+ } catch {
449
+ responseBody = "[Unable to read response body]";
450
+ }
451
+ }
452
+ const entry = {
453
+ url,
454
+ method,
455
+ status: response.status,
456
+ statusText: response.statusText,
457
+ failed,
458
+ requestHeaders: sanitizeHeaders(
459
+ init?.headers
460
+ ),
461
+ responseHeaders: sanitizeHeaders(response.headers),
462
+ requestBody: truncateBody(requestBody, captureOptions2.maxBodySize),
463
+ responseBody: truncateBody(responseBody, captureOptions2.maxBodySize),
464
+ duration,
465
+ timestamp: startTime
466
+ };
467
+ addCapturedRequest(entry);
468
+ }
469
+ return response;
470
+ } catch (error) {
471
+ const duration = Date.now() - startTime;
472
+ if (shouldCapture(url, method, true)) {
473
+ const entry = {
474
+ url,
475
+ method,
476
+ status: 0,
477
+ statusText: "Network Error",
478
+ failed: true,
479
+ requestBody: truncateBody(requestBody, captureOptions2.maxBodySize),
480
+ duration,
481
+ timestamp: startTime,
482
+ error: error instanceof Error ? error.message : String(error)
483
+ };
484
+ addCapturedRequest(entry);
485
+ }
486
+ throw error;
487
+ }
488
+ };
489
+ }
490
+ function startNetworkCapture(options = {}) {
491
+ if (!isBrowser3) {
492
+ console.warn("Network capture is only available in browser environment");
493
+ return;
494
+ }
495
+ if (isCapturing2) {
496
+ console.warn("Network capture already active");
497
+ return;
498
+ }
499
+ captureOptions2 = { ...DEFAULT_OPTIONS3, ...options };
500
+ isCapturing2 = true;
501
+ window.fetch = createFetchInterceptor();
502
+ XMLHttpRequest.prototype.open = function(method, url, async = true, username, password) {
503
+ this._captureData = {
504
+ method: method.toUpperCase(),
505
+ url: url.toString(),
506
+ startTime: 0
507
+ };
508
+ return originalXHROpen.call(
509
+ this,
510
+ method,
511
+ url,
512
+ async,
513
+ username,
514
+ password
515
+ );
516
+ };
517
+ XMLHttpRequest.prototype.send = function(body) {
518
+ const xhr = this;
519
+ if (xhr._captureData) {
520
+ xhr._captureData.startTime = Date.now();
521
+ if (captureOptions2.captureRequestBody && body) {
522
+ try {
523
+ if (typeof body === "string") {
524
+ xhr._captureData.requestBody = JSON.parse(body);
525
+ } else {
526
+ xhr._captureData.requestBody = body;
527
+ }
528
+ } catch {
529
+ xhr._captureData.requestBody = body;
530
+ }
531
+ }
532
+ const originalOnReadyStateChange = xhr.onreadystatechange;
533
+ xhr.onreadystatechange = function(event) {
534
+ if (xhr.readyState === XMLHttpRequest.DONE) {
535
+ const duration = Date.now() - xhr._captureData.startTime;
536
+ const failed = xhr.status === 0 || xhr.status >= 400;
537
+ if (shouldCapture(xhr._captureData.url, xhr._captureData.method, failed)) {
538
+ let responseBody;
539
+ if (captureOptions2.captureResponseBody && failed) {
540
+ try {
541
+ responseBody = xhr.responseType === "" || xhr.responseType === "text" ? JSON.parse(xhr.responseText) : xhr.response;
542
+ } catch {
543
+ responseBody = xhr.responseText || xhr.response;
544
+ }
545
+ }
546
+ const entry = {
547
+ url: xhr._captureData.url,
548
+ method: xhr._captureData.method,
549
+ status: xhr.status,
550
+ statusText: xhr.statusText,
551
+ failed,
552
+ requestBody: truncateBody(
553
+ xhr._captureData.requestBody,
554
+ captureOptions2.maxBodySize
555
+ ),
556
+ responseBody: truncateBody(
557
+ responseBody,
558
+ captureOptions2.maxBodySize
559
+ ),
560
+ duration,
561
+ timestamp: xhr._captureData.startTime
562
+ };
563
+ addCapturedRequest(entry);
564
+ }
565
+ }
566
+ if (originalOnReadyStateChange) {
567
+ originalOnReadyStateChange.call(xhr, event);
568
+ }
569
+ };
570
+ }
571
+ return originalXHRSend.call(this, body);
572
+ };
573
+ }
574
+ function stopNetworkCapture() {
575
+ if (!isBrowser3 || !isCapturing2) {
576
+ return;
577
+ }
578
+ isCapturing2 = false;
579
+ window.fetch = originalFetch;
580
+ XMLHttpRequest.prototype.open = originalXHROpen;
581
+ XMLHttpRequest.prototype.send = originalXHRSend;
582
+ }
583
+ function getNetworkRequests(options = {}) {
584
+ const opts = { ...DEFAULT_OPTIONS3, ...options };
585
+ let requests = [...capturedRequests];
586
+ if (opts.failedOnly) {
587
+ requests = requests.filter((r) => r.failed);
588
+ }
589
+ if (opts.methods.length < DEFAULT_OPTIONS3.methods.length) {
590
+ requests = requests.filter((r) => opts.methods.includes(r.method));
591
+ }
592
+ if (opts.includeUrls.length > 0) {
593
+ requests = requests.filter((r) => matchesPatterns(r.url, opts.includeUrls));
594
+ }
595
+ if (opts.excludeUrls.length > 0) {
596
+ requests = requests.filter(
597
+ (r) => !matchesPatterns(r.url, opts.excludeUrls)
598
+ );
599
+ }
600
+ const totalCaptured = requests.length;
601
+ requests = requests.slice(-opts.limit);
602
+ return {
603
+ requests,
604
+ totalCaptured
605
+ };
606
+ }
607
+ function clearNetworkRequests() {
608
+ capturedRequests = [];
609
+ }
610
+ function isNetworkCaptureActive() {
611
+ return isCapturing2;
612
+ }
613
+ function getFailedRequests(limit = 20) {
614
+ return getNetworkRequests({ failedOnly: true, limit }).requests;
615
+ }
616
+ function formatRequestsForAI(requests) {
617
+ if (requests.length === 0) {
618
+ return "No network requests captured.";
619
+ }
620
+ const formatted = requests.map((req, index) => {
621
+ const time = new Date(req.timestamp).toISOString();
622
+ const statusIcon = req.failed ? "\u274C" : "\u2705";
623
+ let text = `[${index + 1}] ${statusIcon} ${req.method} ${req.url}
624
+ `;
625
+ text += ` Status: ${req.status} ${req.statusText}
626
+ `;
627
+ text += ` Duration: ${req.duration}ms
628
+ `;
629
+ text += ` Time: ${time}`;
630
+ if (req.error) {
631
+ text += `
632
+ Error: ${req.error}`;
633
+ }
634
+ if (req.responseBody && req.failed) {
635
+ const bodyStr = typeof req.responseBody === "string" ? req.responseBody : JSON.stringify(req.responseBody, null, 2);
636
+ text += `
637
+ Response Body:
638
+ ${bodyStr.split("\n").join("\n ")}`;
639
+ }
640
+ return text;
641
+ });
642
+ return `Network Requests (${requests.length} entries):
643
+
644
+ ${formatted.join("\n\n")}`;
645
+ }
646
+ if (isBrowser3) {
647
+ window.addEventListener("beforeunload", () => {
648
+ stopNetworkCapture();
649
+ });
650
+ }
651
+
652
+ // src/core/tools/intentDetector.ts
653
+ var SCREENSHOT_KEYWORDS = [
654
+ // Visual references
655
+ "see",
656
+ "seeing",
657
+ "look",
658
+ "looking",
659
+ "looks",
660
+ "appear",
661
+ "appears",
662
+ "show",
663
+ "showing",
664
+ "shows",
665
+ "display",
666
+ "displays",
667
+ "displayed",
668
+ "visible",
669
+ "invisible",
670
+ // UI elements
671
+ "screen",
672
+ "page",
673
+ "ui",
674
+ "interface",
675
+ "layout",
676
+ "design",
677
+ "button",
678
+ "input",
679
+ "form",
680
+ "modal",
681
+ "popup",
682
+ "menu",
683
+ "dropdown",
684
+ "sidebar",
685
+ "header",
686
+ "footer",
687
+ "navbar",
688
+ "navigation",
689
+ "image",
690
+ "icon",
691
+ "text",
692
+ "font",
693
+ "color",
694
+ "style",
695
+ "css",
696
+ "alignment",
697
+ "position",
698
+ "spacing",
699
+ // Visual issues
700
+ "broken",
701
+ "misaligned",
702
+ "overlapping",
703
+ "cutoff",
704
+ "overflow",
705
+ "blank",
706
+ "empty",
707
+ "missing",
708
+ "wrong",
709
+ "weird",
710
+ "strange",
711
+ "different",
712
+ "changed"
713
+ ];
714
+ var CONSOLE_KEYWORDS = [
715
+ // Errors
716
+ "error",
717
+ "errors",
718
+ "exception",
719
+ "exceptions",
720
+ "crash",
721
+ "crashed",
722
+ "crashing",
723
+ "bug",
724
+ "bugs",
725
+ "buggy",
726
+ "broken",
727
+ "break",
728
+ "breaks",
729
+ // Issues
730
+ "issue",
731
+ "issues",
732
+ "problem",
733
+ "problems",
734
+ "not working",
735
+ "doesnt work",
736
+ "doesn't work",
737
+ "stopped working",
738
+ "fails",
739
+ "failed",
740
+ "failing",
741
+ "failure",
742
+ // Debug references
743
+ "debug",
744
+ "debugging",
745
+ "console",
746
+ "log",
747
+ "logs",
748
+ "warning",
749
+ "warnings",
750
+ "warn",
751
+ "stack",
752
+ "stacktrace",
753
+ "trace",
754
+ "traceback",
755
+ // State issues
756
+ "undefined",
757
+ "null",
758
+ "nan",
759
+ "typeerror",
760
+ "referenceerror",
761
+ "syntaxerror",
762
+ "unexpected",
763
+ "uncaught"
764
+ ];
765
+ var NETWORK_KEYWORDS = [
766
+ // API references
767
+ "api",
768
+ "apis",
769
+ "endpoint",
770
+ "endpoints",
771
+ "request",
772
+ "requests",
773
+ "response",
774
+ "responses",
775
+ "fetch",
776
+ "fetching",
777
+ // HTTP
778
+ "http",
779
+ "https",
780
+ "rest",
781
+ "graphql",
782
+ "post",
783
+ "get",
784
+ "put",
785
+ "delete",
786
+ "patch",
787
+ // Issues
788
+ "timeout",
789
+ "timeouts",
790
+ "timed out",
791
+ "slow",
792
+ "loading",
793
+ "loads",
794
+ "load",
795
+ "forever",
796
+ // Status
797
+ "404",
798
+ "500",
799
+ "401",
800
+ "403",
801
+ "400",
802
+ "not found",
803
+ "unauthorized",
804
+ "forbidden",
805
+ "server error",
806
+ "bad request",
807
+ // Data
808
+ "data",
809
+ "json",
810
+ "payload",
811
+ "body",
812
+ "headers",
813
+ "cors",
814
+ "network",
815
+ "connection",
816
+ "backend",
817
+ "server"
818
+ ];
819
+ var DEFAULT_THRESHOLDS = {
820
+ suggest: 0.3};
821
+ function normalizeText(text) {
822
+ return text.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
823
+ }
824
+ function findMatches(text, keywords) {
825
+ const normalizedText = normalizeText(text);
826
+ const words = new Set(normalizedText.split(" "));
827
+ const matches = [];
828
+ for (const keyword of keywords) {
829
+ const normalizedKeyword = normalizeText(keyword);
830
+ if (words.has(normalizedKeyword)) {
831
+ matches.push(keyword);
832
+ continue;
833
+ }
834
+ if (normalizedKeyword.includes(" ") && normalizedText.includes(normalizedKeyword)) {
835
+ matches.push(keyword);
836
+ continue;
837
+ }
838
+ const pattern = new RegExp(`\\b${normalizedKeyword}`, "i");
839
+ if (pattern.test(normalizedText)) {
840
+ matches.push(keyword);
841
+ }
842
+ }
843
+ return [...new Set(matches)];
844
+ }
845
+ function calculateConfidence(matches, totalKeywords, textLength) {
846
+ if (matches.length === 0) return 0;
847
+ const matchRatio = Math.min(matches.length / 5, 1);
848
+ const multiMatchBonus = matches.length > 2 ? 0.2 : matches.length > 1 ? 0.1 : 0;
849
+ const lengthPenalty = textLength < 20 ? 0.2 : 0;
850
+ return Math.min(matchRatio * 0.7 + multiMatchBonus - lengthPenalty, 1);
851
+ }
852
+ function detectIntent(message) {
853
+ const screenshotMatches = findMatches(message, SCREENSHOT_KEYWORDS);
854
+ const consoleMatches = findMatches(message, CONSOLE_KEYWORDS);
855
+ const networkMatches = findMatches(message, NETWORK_KEYWORDS);
856
+ const textLength = message.length;
857
+ const confidence = {
858
+ screenshot: calculateConfidence(
859
+ screenshotMatches,
860
+ SCREENSHOT_KEYWORDS.length,
861
+ textLength
862
+ ),
863
+ console: calculateConfidence(
864
+ consoleMatches,
865
+ CONSOLE_KEYWORDS.length,
866
+ textLength
867
+ ),
868
+ network: calculateConfidence(
869
+ networkMatches,
870
+ NETWORK_KEYWORDS.length,
871
+ textLength
872
+ )
873
+ };
874
+ const suggestedTools = [];
875
+ if (confidence.screenshot >= DEFAULT_THRESHOLDS.suggest) {
876
+ suggestedTools.push("screenshot");
877
+ }
878
+ if (confidence.console >= DEFAULT_THRESHOLDS.suggest) {
879
+ suggestedTools.push("console");
880
+ }
881
+ if (confidence.network >= DEFAULT_THRESHOLDS.suggest) {
882
+ suggestedTools.push("network");
883
+ }
884
+ suggestedTools.sort((a, b) => confidence[b] - confidence[a]);
885
+ return {
886
+ suggestedTools,
887
+ confidence,
888
+ matchedKeywords: {
889
+ screenshot: screenshotMatches,
890
+ console: consoleMatches,
891
+ network: networkMatches
892
+ }
893
+ };
894
+ }
895
+ function hasToolSuggestions(message) {
896
+ const result = detectIntent(message);
897
+ return result.suggestedTools.length > 0;
898
+ }
899
+ function getPrimaryTool(message) {
900
+ const result = detectIntent(message);
901
+ return result.suggestedTools[0] || null;
902
+ }
903
+ function generateSuggestionReason(result) {
904
+ if (result.suggestedTools.length === 0) {
905
+ return "";
906
+ }
907
+ const reasons = [];
908
+ if (result.suggestedTools.includes("screenshot")) {
909
+ const keywords = result.matchedKeywords.screenshot.slice(0, 3);
910
+ reasons.push(`visual elements mentioned (${keywords.join(", ")})`);
911
+ }
912
+ if (result.suggestedTools.includes("console")) {
913
+ const keywords = result.matchedKeywords.console.slice(0, 3);
914
+ reasons.push(`potential errors indicated (${keywords.join(", ")})`);
915
+ }
916
+ if (result.suggestedTools.includes("network")) {
917
+ const keywords = result.matchedKeywords.network.slice(0, 3);
918
+ reasons.push(`API/network issues suggested (${keywords.join(", ")})`);
919
+ }
920
+ return `Based on your message: ${reasons.join("; ")}.`;
921
+ }
922
+ function createCustomDetector(customKeywords) {
923
+ const extendedScreenshot = [
924
+ ...SCREENSHOT_KEYWORDS,
925
+ ...customKeywords.screenshot || []
926
+ ];
927
+ const extendedConsole = [
928
+ ...CONSOLE_KEYWORDS,
929
+ ...customKeywords.console || []
930
+ ];
931
+ const extendedNetwork = [
932
+ ...NETWORK_KEYWORDS,
933
+ ...customKeywords.network || []
934
+ ];
935
+ return function detectCustomIntent(message) {
936
+ const screenshotMatches = findMatches(message, extendedScreenshot);
937
+ const consoleMatches = findMatches(message, extendedConsole);
938
+ const networkMatches = findMatches(message, extendedNetwork);
939
+ const textLength = message.length;
940
+ const confidence = {
941
+ screenshot: calculateConfidence(
942
+ screenshotMatches,
943
+ extendedScreenshot.length,
944
+ textLength
945
+ ),
946
+ console: calculateConfidence(
947
+ consoleMatches,
948
+ extendedConsole.length,
949
+ textLength
950
+ ),
951
+ network: calculateConfidence(
952
+ networkMatches,
953
+ extendedNetwork.length,
954
+ textLength
955
+ )
956
+ };
957
+ const suggestedTools = [];
958
+ if (confidence.screenshot >= DEFAULT_THRESHOLDS.suggest) {
959
+ suggestedTools.push("screenshot");
960
+ }
961
+ if (confidence.console >= DEFAULT_THRESHOLDS.suggest) {
962
+ suggestedTools.push("console");
963
+ }
964
+ if (confidence.network >= DEFAULT_THRESHOLDS.suggest) {
965
+ suggestedTools.push("network");
966
+ }
967
+ suggestedTools.sort((a, b) => confidence[b] - confidence[a]);
968
+ return {
969
+ suggestedTools,
970
+ confidence,
971
+ matchedKeywords: {
972
+ screenshot: screenshotMatches,
973
+ console: consoleMatches,
974
+ network: networkMatches
975
+ }
976
+ };
977
+ };
978
+ }
979
+
980
+ // src/core/types/tools.ts
981
+ function tool(config) {
982
+ return {
983
+ description: config.description,
984
+ location: config.location ?? "client",
985
+ // Display configuration
986
+ title: config.title,
987
+ executingTitle: config.executingTitle,
988
+ completedTitle: config.completedTitle,
989
+ // Schema and handlers
990
+ inputSchema: config.inputSchema ?? {
991
+ type: "object",
992
+ properties: {},
993
+ required: []
994
+ },
995
+ handler: config.handler,
996
+ render: config.render,
997
+ available: config.available,
998
+ needsApproval: config.needsApproval,
999
+ approvalMessage: config.approvalMessage,
1000
+ aiResponseMode: config.aiResponseMode,
1001
+ aiContext: config.aiContext
1002
+ };
1003
+ }
1004
+ function toolToOpenAIFormat(tool2) {
1005
+ return {
1006
+ type: "function",
1007
+ function: {
1008
+ name: tool2.name,
1009
+ description: tool2.description,
1010
+ parameters: tool2.inputSchema
1011
+ }
1012
+ };
1013
+ }
1014
+ function toolToAnthropicFormat(tool2) {
1015
+ return {
1016
+ name: tool2.name,
1017
+ description: tool2.description,
1018
+ input_schema: tool2.inputSchema
1019
+ };
1020
+ }
1021
+ function createToolResult(toolCallId, response) {
1022
+ return {
1023
+ toolCallId,
1024
+ content: JSON.stringify(response),
1025
+ success: response.success,
1026
+ error: response.error
1027
+ };
1028
+ }
1029
+ function success(data, message) {
1030
+ return {
1031
+ success: true,
1032
+ data,
1033
+ message
1034
+ };
1035
+ }
1036
+ function failure(error) {
1037
+ return {
1038
+ success: false,
1039
+ error
1040
+ };
1041
+ }
1042
+
1043
+ // src/core/tools/builtin/screenshot.ts
1044
+ var screenshotTool = tool({
1045
+ description: "Capture a screenshot of the user's current screen/viewport. Use this when the user asks you to look at their screen, see what they're seeing, help with visual issues, or debug UI problems.",
1046
+ location: "client",
1047
+ inputSchema: {
1048
+ type: "object",
1049
+ properties: {
1050
+ quality: {
1051
+ type: "number",
1052
+ description: "Image quality from 0 to 1 (default: 0.8)",
1053
+ minimum: 0,
1054
+ maximum: 1
1055
+ }
1056
+ },
1057
+ required: []
1058
+ },
1059
+ needsApproval: true,
1060
+ approvalMessage: "Allow AI to capture a screenshot of your screen?",
1061
+ handler: async (params) => {
1062
+ if (!isScreenshotSupported()) {
1063
+ return failure("Screenshot capture is not supported in this environment");
1064
+ }
1065
+ try {
1066
+ const options = {};
1067
+ if (params.quality !== void 0) {
1068
+ options.quality = params.quality;
1069
+ }
1070
+ const result = await captureScreenshot(options);
1071
+ return {
1072
+ success: true,
1073
+ message: `Screenshot captured (${result.width}x${result.height}). The image is shared in the conversation.`,
1074
+ addAsUserMessage: true,
1075
+ data: {
1076
+ attachment: {
1077
+ type: "image",
1078
+ data: result.data,
1079
+ mimeType: `image/${result.format}`,
1080
+ filename: "screenshot.png"
1081
+ },
1082
+ dimensions: {
1083
+ width: result.width,
1084
+ height: result.height
1085
+ }
1086
+ }
1087
+ };
1088
+ } catch (error) {
1089
+ return failure(
1090
+ error instanceof Error ? error.message : "Screenshot capture failed"
1091
+ );
1092
+ }
1093
+ }
1094
+ });
1095
+ function createScreenshotTool(options) {
1096
+ return tool({
1097
+ ...screenshotTool,
1098
+ needsApproval: options?.needsApproval ?? true,
1099
+ approvalMessage: options?.approvalMessage ?? "Allow AI to capture a screenshot of your screen?",
1100
+ handler: async (params) => {
1101
+ if (!isScreenshotSupported()) {
1102
+ return failure(
1103
+ "Screenshot capture is not supported in this environment"
1104
+ );
1105
+ }
1106
+ try {
1107
+ const result = await captureScreenshot({
1108
+ quality: params.quality ?? options?.defaultQuality ?? 0.8
1109
+ });
1110
+ return {
1111
+ success: true,
1112
+ message: `Screenshot captured (${result.width}x${result.height}). The image is shared in the conversation.`,
1113
+ addAsUserMessage: true,
1114
+ data: {
1115
+ attachment: {
1116
+ type: "image",
1117
+ data: result.data,
1118
+ mimeType: `image/${result.format}`,
1119
+ filename: "screenshot.png"
1120
+ },
1121
+ dimensions: {
1122
+ width: result.width,
1123
+ height: result.height
1124
+ }
1125
+ }
1126
+ };
1127
+ } catch (error) {
1128
+ return failure(
1129
+ error instanceof Error ? error.message : "Screenshot capture failed"
1130
+ );
1131
+ }
1132
+ }
1133
+ });
1134
+ }
1135
+
1136
+ // src/core/tools/builtin/console.ts
1137
+ var consoleLogsTool = tool({
1138
+ description: "Get recent console logs from the browser. Use this when debugging JavaScript errors, checking for warnings, or understanding what's happening in the application.",
1139
+ location: "client",
1140
+ inputSchema: {
1141
+ type: "object",
1142
+ properties: {
1143
+ limit: {
1144
+ type: "number",
1145
+ description: "Maximum number of logs to return (default: 50)"
1146
+ },
1147
+ types: {
1148
+ type: "array",
1149
+ description: "Filter by log types: 'error', 'warn', 'info', 'log', 'debug'",
1150
+ items: {
1151
+ type: "string",
1152
+ enum: ["error", "warn", "info", "log", "debug"]
1153
+ }
1154
+ }
1155
+ },
1156
+ required: []
1157
+ },
1158
+ needsApproval: true,
1159
+ approvalMessage: "Allow AI to access browser console logs?",
1160
+ handler: async (params) => {
1161
+ try {
1162
+ if (!isConsoleCaptureActive()) {
1163
+ startConsoleCapture();
1164
+ }
1165
+ const logs = getConsoleLogs({
1166
+ limit: params.limit || 50,
1167
+ types: params.types
1168
+ });
1169
+ const formattedLogs = formatLogsForAI(logs.logs);
1170
+ return success(
1171
+ {
1172
+ logs: formattedLogs,
1173
+ count: logs.logs.length,
1174
+ totalCaptured: logs.totalCaptured
1175
+ },
1176
+ `Retrieved ${logs.logs.length} console logs`
1177
+ );
1178
+ } catch (error) {
1179
+ return failure(
1180
+ error instanceof Error ? error.message : "Failed to get console logs"
1181
+ );
1182
+ }
1183
+ }
1184
+ });
1185
+ function createConsoleLogsTool(options) {
1186
+ return tool({
1187
+ ...consoleLogsTool,
1188
+ needsApproval: options?.needsApproval ?? true,
1189
+ approvalMessage: options?.approvalMessage ?? "Allow AI to access browser console logs?",
1190
+ handler: async (params) => {
1191
+ try {
1192
+ if (!isConsoleCaptureActive()) {
1193
+ startConsoleCapture();
1194
+ }
1195
+ const logs = getConsoleLogs({
1196
+ limit: params.limit || options?.defaultLimit || 50,
1197
+ types: params.types
1198
+ });
1199
+ const formattedLogs = formatLogsForAI(logs.logs);
1200
+ return success(
1201
+ {
1202
+ logs: formattedLogs,
1203
+ count: logs.logs.length,
1204
+ totalCaptured: logs.totalCaptured
1205
+ },
1206
+ `Retrieved ${logs.logs.length} console logs`
1207
+ );
1208
+ } catch (error) {
1209
+ return failure(
1210
+ error instanceof Error ? error.message : "Failed to get console logs"
1211
+ );
1212
+ }
1213
+ }
1214
+ });
1215
+ }
1216
+
1217
+ // src/core/tools/builtin/network.ts
1218
+ var networkRequestsTool = tool({
1219
+ description: "Get recent network requests from the browser. Use this when debugging API calls, checking for failed requests, analyzing network activity, or troubleshooting connectivity issues.",
1220
+ location: "client",
1221
+ inputSchema: {
1222
+ type: "object",
1223
+ properties: {
1224
+ limit: {
1225
+ type: "number",
1226
+ description: "Maximum number of requests to return (default: 20)"
1227
+ },
1228
+ failedOnly: {
1229
+ type: "boolean",
1230
+ description: "Only return failed requests (status >= 400)"
1231
+ }
1232
+ },
1233
+ required: []
1234
+ },
1235
+ needsApproval: true,
1236
+ approvalMessage: "Allow AI to access network request history?",
1237
+ handler: async (params) => {
1238
+ try {
1239
+ if (!isNetworkCaptureActive()) {
1240
+ startNetworkCapture();
1241
+ }
1242
+ const requests = getNetworkRequests({
1243
+ limit: params.limit || 20,
1244
+ failedOnly: params.failedOnly
1245
+ });
1246
+ const formattedRequests = formatRequestsForAI(requests.requests);
1247
+ return success(
1248
+ {
1249
+ requests: formattedRequests,
1250
+ count: requests.requests.length,
1251
+ totalCaptured: requests.totalCaptured
1252
+ },
1253
+ `Retrieved ${requests.requests.length} network requests`
1254
+ );
1255
+ } catch (error) {
1256
+ return failure(
1257
+ error instanceof Error ? error.message : "Failed to get network requests"
1258
+ );
1259
+ }
1260
+ }
1261
+ });
1262
+ function createNetworkRequestsTool(options) {
1263
+ return tool({
1264
+ ...networkRequestsTool,
1265
+ needsApproval: options?.needsApproval ?? true,
1266
+ approvalMessage: options?.approvalMessage ?? "Allow AI to access network request history?",
1267
+ handler: async (params) => {
1268
+ try {
1269
+ if (!isNetworkCaptureActive()) {
1270
+ startNetworkCapture();
1271
+ }
1272
+ const requests = getNetworkRequests({
1273
+ limit: params.limit || options?.defaultLimit || 20,
1274
+ failedOnly: params.failedOnly
1275
+ });
1276
+ const formattedRequests = formatRequestsForAI(requests.requests);
1277
+ return success(
1278
+ {
1279
+ requests: formattedRequests,
1280
+ count: requests.requests.length,
1281
+ totalCaptured: requests.totalCaptured
1282
+ },
1283
+ `Retrieved ${requests.requests.length} network requests`
1284
+ );
1285
+ } catch (error) {
1286
+ return failure(
1287
+ error instanceof Error ? error.message : "Failed to get network requests"
1288
+ );
1289
+ }
1290
+ }
1291
+ });
1292
+ }
1293
+
1294
+ // src/core/tools/builtin/index.ts
1295
+ var builtinTools = {
1296
+ capture_screenshot: {
1297
+ name: "capture_screenshot",
1298
+ ...screenshotTool
1299
+ },
1300
+ get_console_logs: {
1301
+ name: "get_console_logs",
1302
+ ...consoleLogsTool
1303
+ },
1304
+ get_network_requests: {
1305
+ name: "get_network_requests",
1306
+ ...networkRequestsTool
1307
+ }
1308
+ };
1309
+
1310
+ // src/core/utils/id.ts
1311
+ function generateId(prefix = "id") {
1312
+ return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1313
+ }
1314
+ function generateMessageId() {
1315
+ return generateId("msg");
1316
+ }
1317
+ function generateThreadId() {
1318
+ return generateId("thread");
1319
+ }
1320
+ function generateToolCallId() {
1321
+ return generateId("call");
1322
+ }
1323
+
1324
+ // src/core/types/message.ts
1325
+ function parseToolCallArgs(toolCall) {
1326
+ try {
1327
+ return JSON.parse(toolCall.function.arguments);
1328
+ } catch {
1329
+ return {};
1330
+ }
1331
+ }
1332
+ function createToolCall(id, name, args) {
1333
+ return {
1334
+ id,
1335
+ type: "function",
1336
+ function: {
1337
+ name,
1338
+ arguments: JSON.stringify(args)
1339
+ }
1340
+ };
1341
+ }
1342
+ function createMessage(partial) {
1343
+ return {
1344
+ id: partial.id ?? generateMessageId(),
1345
+ thread_id: partial.thread_id,
1346
+ role: partial.role,
1347
+ content: partial.content ?? null,
1348
+ tool_calls: partial.tool_calls,
1349
+ tool_call_id: partial.tool_call_id,
1350
+ metadata: partial.metadata,
1351
+ created_at: partial.created_at ?? /* @__PURE__ */ new Date()
1352
+ };
1353
+ }
1354
+ function createUserMessage(content, options) {
1355
+ return createMessage({
1356
+ id: options?.id,
1357
+ thread_id: options?.thread_id,
1358
+ role: "user",
1359
+ content,
1360
+ metadata: options?.attachments ? { attachments: options.attachments } : void 0
1361
+ });
1362
+ }
1363
+ function createAssistantMessage(content, options) {
1364
+ const metadata = {};
1365
+ if (options?.thinking) metadata.thinking = options.thinking;
1366
+ if (options?.sources) metadata.sources = options.sources;
1367
+ if (options?.model) metadata.model = options.model;
1368
+ return createMessage({
1369
+ id: options?.id,
1370
+ thread_id: options?.thread_id,
1371
+ role: "assistant",
1372
+ content,
1373
+ tool_calls: options?.tool_calls,
1374
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0
1375
+ });
1376
+ }
1377
+ function createToolMessage(toolCallId, result, options) {
1378
+ return createMessage({
1379
+ id: options?.id,
1380
+ thread_id: options?.thread_id,
1381
+ role: "tool",
1382
+ content: JSON.stringify(result),
1383
+ tool_call_id: toolCallId
1384
+ });
1385
+ }
1386
+ function hasToolCalls(message) {
1387
+ return message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
1388
+ }
1389
+ function isToolResult(message) {
1390
+ return message.role === "tool" && !!message.tool_call_id;
1391
+ }
1392
+
1393
+ // src/core/types/config.ts
1394
+ var DEFAULT_MODELS = {
1395
+ openai: "gpt-4o",
1396
+ anthropic: "claude-3-5-sonnet-latest",
1397
+ google: "gemini-pro",
1398
+ groq: "llama-3.1-70b-versatile",
1399
+ ollama: "llama3",
1400
+ custom: "default"
1401
+ };
1402
+ function getDefaultModel(provider) {
1403
+ return DEFAULT_MODELS[provider] || "default";
1404
+ }
1405
+
1406
+ // src/core/types/actions.ts
1407
+ function actionToTool(action) {
1408
+ const properties = {};
1409
+ const required = [];
1410
+ if (action.parameters) {
1411
+ for (const [name, param] of Object.entries(action.parameters)) {
1412
+ properties[name] = parameterToJsonSchema(param);
1413
+ if (param.required) {
1414
+ required.push(name);
1415
+ }
1416
+ }
1417
+ }
1418
+ return {
1419
+ type: "function",
1420
+ function: {
1421
+ name: action.name,
1422
+ description: action.description,
1423
+ parameters: {
1424
+ type: "object",
1425
+ properties,
1426
+ required: required.length > 0 ? required : void 0
1427
+ }
1428
+ }
1429
+ };
1430
+ }
1431
+ function parameterToJsonSchema(param) {
1432
+ const schema = {
1433
+ type: param.type
1434
+ };
1435
+ if (param.description) {
1436
+ schema.description = param.description;
1437
+ }
1438
+ if (param.enum) {
1439
+ schema.enum = param.enum;
1440
+ }
1441
+ if (param.default !== void 0) {
1442
+ schema.default = param.default;
1443
+ }
1444
+ if (param.properties) {
1445
+ schema.properties = {};
1446
+ for (const [name, prop] of Object.entries(param.properties)) {
1447
+ schema.properties[name] = parameterToJsonSchema(prop);
1448
+ }
1449
+ }
1450
+ if (param.items) {
1451
+ schema.items = parameterToJsonSchema(param.items);
1452
+ }
1453
+ return schema;
1454
+ }
1455
+
1456
+ // src/core/types/events.ts
1457
+ function parseStreamEvent(data) {
1458
+ try {
1459
+ return JSON.parse(data);
1460
+ } catch {
1461
+ return null;
1462
+ }
1463
+ }
1464
+ function serializeStreamEvent(event) {
1465
+ return JSON.stringify(event);
1466
+ }
1467
+ function formatSSE(event) {
1468
+ return `data: ${serializeStreamEvent(event)}
1469
+
1470
+ `;
1471
+ }
1472
+
1473
+ // src/core/types/thread.ts
1474
+ function generateThreadTitle(content) {
1475
+ const trimmed = content.trim();
1476
+ if (trimmed.length <= 50) return trimmed;
1477
+ return trimmed.substring(0, 47) + "...";
1478
+ }
1479
+
1480
+ // src/core/utils/stream.ts
1481
+ function parseSSELine(line) {
1482
+ if (!line.startsWith("data: ")) {
1483
+ return null;
1484
+ }
1485
+ const data = line.slice(6).trim();
1486
+ if (data === "[DONE]") {
1487
+ return { type: "done" };
1488
+ }
1489
+ try {
1490
+ return JSON.parse(data);
1491
+ } catch {
1492
+ return null;
1493
+ }
1494
+ }
1495
+ async function* streamSSE(response) {
1496
+ if (!response.body) {
1497
+ throw new Error("Response body is null");
1498
+ }
1499
+ const reader = response.body.getReader();
1500
+ const decoder = new TextDecoder();
1501
+ let buffer = "";
1502
+ try {
1503
+ while (true) {
1504
+ const { done, value } = await reader.read();
1505
+ if (done) {
1506
+ break;
1507
+ }
1508
+ buffer += decoder.decode(value, { stream: true });
1509
+ const lines = buffer.split("\n");
1510
+ buffer = lines.pop() || "";
1511
+ for (const line of lines) {
1512
+ const event = parseSSELine(line);
1513
+ if (event) {
1514
+ yield event;
1515
+ }
1516
+ }
1517
+ }
1518
+ if (buffer.trim()) {
1519
+ const event = parseSSELine(buffer);
1520
+ if (event) {
1521
+ yield event;
1522
+ }
1523
+ }
1524
+ } finally {
1525
+ reader.releaseLock();
1526
+ }
1527
+ }
1528
+ function createSSEStream(generator) {
1529
+ const encoder = new TextEncoder();
1530
+ return new ReadableStream({
1531
+ async start(controller) {
1532
+ try {
1533
+ for await (const event of generator) {
1534
+ const data = `data: ${JSON.stringify(event)}
1535
+
1536
+ `;
1537
+ controller.enqueue(encoder.encode(data));
1538
+ }
1539
+ controller.enqueue(encoder.encode("data: [DONE]\n\n"));
1540
+ controller.close();
1541
+ } catch (error) {
1542
+ const errorEvent = {
1543
+ type: "error",
1544
+ message: error instanceof Error ? error.message : "Unknown error"
1545
+ };
1546
+ controller.enqueue(
1547
+ encoder.encode(`data: ${JSON.stringify(errorEvent)}
1548
+
1549
+ `)
1550
+ );
1551
+ controller.close();
1552
+ }
1553
+ }
1554
+ });
1555
+ }
1556
+
1557
+ // src/core/utils/zod-to-json-schema.ts
1558
+ function isZodSchema(value) {
1559
+ return value !== null && typeof value === "object" && "_def" in value && typeof value._def === "object";
1560
+ }
1561
+ function getZodTypeName(schema) {
1562
+ if (!isZodSchema(schema)) return "unknown";
1563
+ const def = schema._def;
1564
+ return def.typeName || "unknown";
1565
+ }
1566
+ function getZodDescription(schema) {
1567
+ if (!isZodSchema(schema)) return void 0;
1568
+ const def = schema._def;
1569
+ return def.description;
1570
+ }
1571
+ function zodToJsonSchema(schema) {
1572
+ if (!isZodSchema(schema)) {
1573
+ return { type: "string" };
1574
+ }
1575
+ const typeName = getZodTypeName(schema);
1576
+ const description = getZodDescription(schema);
1577
+ const def = schema._def;
1578
+ switch (typeName) {
1579
+ case "ZodString": {
1580
+ const result2 = { type: "string" };
1581
+ if (description) result2.description = description;
1582
+ const checks = def.checks;
1583
+ if (checks) {
1584
+ for (const check of checks) {
1585
+ if (check.kind === "min") result2.minLength = check.value;
1586
+ if (check.kind === "max") result2.maxLength = check.value;
1587
+ if (check.kind === "regex") result2.pattern = String(check.value);
1588
+ }
1589
+ }
1590
+ return result2;
1591
+ }
1592
+ case "ZodNumber": {
1593
+ const result2 = { type: "number" };
1594
+ if (description) result2.description = description;
1595
+ const checks = def.checks;
1596
+ if (checks) {
1597
+ for (const check of checks) {
1598
+ if (check.kind === "min") result2.minimum = check.value;
1599
+ if (check.kind === "max") result2.maximum = check.value;
1600
+ if (check.kind === "int") result2.type = "integer";
1601
+ }
1602
+ }
1603
+ return result2;
1604
+ }
1605
+ case "ZodBoolean": {
1606
+ const result2 = { type: "boolean" };
1607
+ if (description) result2.description = description;
1608
+ return result2;
1609
+ }
1610
+ case "ZodEnum": {
1611
+ const values = def.values;
1612
+ const result2 = {
1613
+ type: typeof values[0] === "number" ? "number" : "string",
1614
+ enum: values
1615
+ };
1616
+ if (description) result2.description = description;
1617
+ return result2;
1618
+ }
1619
+ case "ZodArray": {
1620
+ const innerType = def.type;
1621
+ const result2 = {
1622
+ type: "array",
1623
+ items: zodToJsonSchema(innerType)
1624
+ };
1625
+ if (description) result2.description = description;
1626
+ return result2;
1627
+ }
1628
+ case "ZodObject": {
1629
+ const shape = def.shape;
1630
+ const shapeObj = typeof shape === "function" ? shape() : shape;
1631
+ const properties = {};
1632
+ const required = [];
1633
+ for (const [key, value] of Object.entries(shapeObj)) {
1634
+ properties[key] = zodToJsonSchema(value);
1635
+ const fieldTypeName = getZodTypeName(value);
1636
+ if (fieldTypeName !== "ZodOptional" && fieldTypeName !== "ZodNullable") {
1637
+ required.push(key);
1638
+ }
1639
+ }
1640
+ const result2 = {
1641
+ type: "object",
1642
+ properties
1643
+ };
1644
+ if (required.length > 0) result2.required = required;
1645
+ if (description) result2.description = description;
1646
+ return result2;
1647
+ }
1648
+ case "ZodOptional":
1649
+ case "ZodNullable": {
1650
+ const innerType = def.innerType;
1651
+ return zodToJsonSchema(innerType);
1652
+ }
1653
+ case "ZodDefault": {
1654
+ const innerType = def.innerType;
1655
+ const defaultValue = def.defaultValue;
1656
+ const result2 = zodToJsonSchema(innerType);
1657
+ result2.default = typeof defaultValue === "function" ? defaultValue() : defaultValue;
1658
+ return result2;
1659
+ }
1660
+ case "ZodLiteral": {
1661
+ const value = def.value;
1662
+ return {
1663
+ type: typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string",
1664
+ enum: [value],
1665
+ description
1666
+ };
1667
+ }
1668
+ case "ZodUnion": {
1669
+ const options = def.options;
1670
+ if (options && options.length > 0) {
1671
+ return zodToJsonSchema(options[0]);
1672
+ }
1673
+ return { type: "string" };
1674
+ }
1675
+ default:
1676
+ const result = { type: "string" };
1677
+ if (description) result.description = description;
1678
+ return result;
1679
+ }
1680
+ }
1681
+ function zodObjectToInputSchema(schema) {
1682
+ const jsonSchema = zodToJsonSchema(schema);
1683
+ if (jsonSchema.type !== "object" || !jsonSchema.properties) {
1684
+ const typeName = getZodTypeName(schema);
1685
+ throw new Error(
1686
+ `Expected a Zod object schema, got ${typeName}. Converted to: ${JSON.stringify(jsonSchema)}`
1687
+ );
1688
+ }
1689
+ return {
1690
+ type: "object",
1691
+ properties: jsonSchema.properties,
1692
+ required: jsonSchema.required
1693
+ };
1694
+ }
1695
+ function defineTool(config) {
1696
+ return {
1697
+ name: config.name,
1698
+ description: config.description,
1699
+ location: config.location,
1700
+ inputSchema: zodObjectToInputSchema(config.schema),
1701
+ handler: config.handler,
1702
+ render: config.render,
1703
+ available: config.available,
1704
+ // Display config
1705
+ title: config.title,
1706
+ executingTitle: config.executingTitle,
1707
+ completedTitle: config.completedTitle,
1708
+ // AI response control
1709
+ aiResponseMode: config.aiResponseMode,
1710
+ aiContext: config.aiContext,
1711
+ // Approval
1712
+ needsApproval: config.needsApproval,
1713
+ approvalMessage: config.approvalMessage
1714
+ };
1715
+ }
1716
+ function defineClientTool(config) {
1717
+ return defineTool({ ...config, location: "client" });
1718
+ }
1719
+ function defineServerTool(config) {
1720
+ return defineTool({ ...config, location: "server" });
1721
+ }
1722
+
1723
+ // src/core/system-prompt.ts
1724
+ function defaultSystemMessage(contextString, additionalInstructions) {
1725
+ return `
1726
+ You are a helpful, efficient, and professional AI assistant.
1727
+
1728
+ Help the user achieve their goals efficiently, without unnecessary fluff, while maintaining professionalism.
1729
+ Be polite, respectful, and prefer brevity over verbosity.
1730
+
1731
+ ${contextString ? `The user has provided you with the following context:
1732
+ \`\`\`
1733
+ ${contextString}
1734
+ \`\`\`
1735
+
1736
+ ` : ""}You have access to functions you can call to take actions or get more information.
1737
+
1738
+ Assist the user as best you can. Ask clarifying questions if needed, but if you can reasonably fill in the blanks yourself, do so.
1739
+
1740
+ When calling a function, call it without extra commentary.
1741
+ If a function returns an error:
1742
+ - If the error is from incorrect parameters, you may retry with corrected arguments.
1743
+ - If the error source is unclear, do not retry.
1744
+ ` + (additionalInstructions ? `
1745
+ ${additionalInstructions}` : "");
1746
+ }
1747
+
1748
+ // src/core/services/storage.ts
1749
+ var CLOUD_MAX_FILE_SIZE = 25 * 1024 * 1024;
1750
+ var DEFAULT_YOURGPT_ENDPOINT = "https://api.yourgpt.ai";
1751
+ function createCloudStorage(config) {
1752
+ const endpoint = config.endpoint || DEFAULT_YOURGPT_ENDPOINT;
1753
+ const maxFileSize = config.maxFileSize || CLOUD_MAX_FILE_SIZE;
1754
+ return {
1755
+ /**
1756
+ * Check if cloud storage is available
1757
+ * Premium API keys start with "ygpt_"
1758
+ */
1759
+ isAvailable() {
1760
+ return Boolean(config.apiKey?.startsWith("ygpt_"));
1761
+ },
1762
+ /**
1763
+ * Upload file to managed cloud storage
1764
+ */
1765
+ async upload(file, options) {
1766
+ if (file.size > maxFileSize) {
1767
+ const sizeMB = (maxFileSize / (1024 * 1024)).toFixed(0);
1768
+ throw new Error(`File size exceeds ${sizeMB}MB limit`);
1769
+ }
1770
+ const presignResponse = await fetch(`${endpoint}/v1/storage/upload-url`, {
1771
+ method: "POST",
1772
+ headers: {
1773
+ Authorization: `Bearer ${config.apiKey}`,
1774
+ "Content-Type": "application/json"
1775
+ },
1776
+ body: JSON.stringify({
1777
+ filename: file.name,
1778
+ mimeType: file.type,
1779
+ size: file.size
1780
+ })
1781
+ });
1782
+ if (!presignResponse.ok) {
1783
+ const error = await presignResponse.text();
1784
+ throw new Error(`Failed to get upload URL: ${error}`);
1785
+ }
1786
+ const { uploadUrl, publicUrl, expiresIn } = await presignResponse.json();
1787
+ const uploadResponse = await fetch(uploadUrl, {
1788
+ method: "PUT",
1789
+ body: file,
1790
+ headers: {
1791
+ "Content-Type": file.type
1792
+ }
1793
+ });
1794
+ if (!uploadResponse.ok) {
1795
+ throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
1796
+ }
1797
+ return {
1798
+ url: publicUrl,
1799
+ expiresAt: expiresIn ? Date.now() + expiresIn * 1e3 : void 0
1800
+ };
1801
+ }
1802
+ };
1803
+ }
1804
+ function getAttachmentTypeFromMime(mimeType) {
1805
+ if (mimeType.startsWith("image/")) return "image";
1806
+ if (mimeType.startsWith("audio/")) return "audio";
1807
+ if (mimeType.startsWith("video/")) return "video";
1808
+ return "file";
1809
+ }
1810
+ async function processFileToAttachment(file, storage) {
1811
+ const type = getAttachmentTypeFromMime(file.type);
1812
+ if (storage?.isAvailable()) {
1813
+ const { url } = await storage.upload(file);
1814
+ return {
1815
+ type,
1816
+ url,
1817
+ mimeType: file.type,
1818
+ filename: file.name
1819
+ };
1820
+ }
1821
+ const data = await fileToBase64(file);
1822
+ return {
1823
+ type,
1824
+ data,
1825
+ mimeType: file.type,
1826
+ filename: file.name
1827
+ };
1828
+ }
1829
+ function fileToBase64(file) {
1830
+ return new Promise((resolve, reject) => {
1831
+ const reader = new FileReader();
1832
+ reader.onload = () => {
1833
+ if (typeof reader.result === "string") {
1834
+ resolve(reader.result);
1835
+ } else {
1836
+ reject(new Error("Failed to read file as base64"));
1837
+ }
1838
+ };
1839
+ reader.onerror = () => reject(new Error("Failed to read file"));
1840
+ reader.readAsDataURL(file);
1841
+ });
1842
+ }
1843
+
1844
+ exports.CLOUD_MAX_FILE_SIZE = CLOUD_MAX_FILE_SIZE;
1845
+ exports.DEFAULT_MODELS = DEFAULT_MODELS;
1846
+ exports.DEFAULT_YOURGPT_ENDPOINT = DEFAULT_YOURGPT_ENDPOINT;
1847
+ exports.actionToTool = actionToTool;
1848
+ exports.builtinTools = builtinTools;
1849
+ exports.captureCurrentLogs = captureCurrentLogs;
1850
+ exports.captureScreenshot = captureScreenshot;
1851
+ exports.clearConsoleLogs = clearConsoleLogs;
1852
+ exports.clearNetworkRequests = clearNetworkRequests;
1853
+ exports.consoleLogsTool = consoleLogsTool;
1854
+ exports.createAssistantMessage = createAssistantMessage;
1855
+ exports.createCloudStorage = createCloudStorage;
1856
+ exports.createConsoleLogsTool = createConsoleLogsTool;
1857
+ exports.createCustomDetector = createCustomDetector;
1858
+ exports.createMessage = createMessage;
1859
+ exports.createNetworkRequestsTool = createNetworkRequestsTool;
1860
+ exports.createSSEStream = createSSEStream;
1861
+ exports.createScreenshotTool = createScreenshotTool;
1862
+ exports.createToolCall = createToolCall;
1863
+ exports.createToolMessage = createToolMessage;
1864
+ exports.createToolResult = createToolResult;
1865
+ exports.createUserMessage = createUserMessage;
1866
+ exports.defaultSystemMessage = defaultSystemMessage;
1867
+ exports.defineClientTool = defineClientTool;
1868
+ exports.defineServerTool = defineServerTool;
1869
+ exports.defineTool = defineTool;
1870
+ exports.detectIntent = detectIntent;
1871
+ exports.failure = failure;
1872
+ exports.formatLogsForAI = formatLogsForAI;
1873
+ exports.formatRequestsForAI = formatRequestsForAI;
1874
+ exports.formatSSE = formatSSE;
1875
+ exports.generateId = generateId;
1876
+ exports.generateMessageId = generateMessageId;
1877
+ exports.generateSuggestionReason = generateSuggestionReason;
1878
+ exports.generateThreadId = generateThreadId;
1879
+ exports.generateThreadTitle = generateThreadTitle;
1880
+ exports.generateToolCallId = generateToolCallId;
1881
+ exports.getAttachmentTypeFromMime = getAttachmentTypeFromMime;
1882
+ exports.getConsoleErrors = getConsoleErrors;
1883
+ exports.getConsoleLogs = getConsoleLogs;
1884
+ exports.getConsoleWarnings = getConsoleWarnings;
1885
+ exports.getDefaultModel = getDefaultModel;
1886
+ exports.getFailedRequests = getFailedRequests;
1887
+ exports.getNetworkRequests = getNetworkRequests;
1888
+ exports.getPrimaryTool = getPrimaryTool;
1889
+ exports.hasToolCalls = hasToolCalls;
1890
+ exports.hasToolSuggestions = hasToolSuggestions;
1891
+ exports.isConsoleCaptureActive = isConsoleCaptureActive;
1892
+ exports.isNetworkCaptureActive = isNetworkCaptureActive;
1893
+ exports.isScreenshotSupported = isScreenshotSupported;
1894
+ exports.isToolResult = isToolResult;
1895
+ exports.networkRequestsTool = networkRequestsTool;
1896
+ exports.parseSSELine = parseSSELine;
1897
+ exports.parseStreamEvent = parseStreamEvent;
1898
+ exports.parseToolCallArgs = parseToolCallArgs;
1899
+ exports.processFileToAttachment = processFileToAttachment;
1900
+ exports.resizeScreenshot = resizeScreenshot;
1901
+ exports.screenshotTool = screenshotTool;
1902
+ exports.serializeStreamEvent = serializeStreamEvent;
1903
+ exports.startConsoleCapture = startConsoleCapture;
1904
+ exports.startNetworkCapture = startNetworkCapture;
1905
+ exports.stopConsoleCapture = stopConsoleCapture;
1906
+ exports.stopNetworkCapture = stopNetworkCapture;
1907
+ exports.streamSSE = streamSSE;
1908
+ exports.success = success;
1909
+ exports.tool = tool;
1910
+ exports.toolToAnthropicFormat = toolToAnthropicFormat;
1911
+ exports.toolToOpenAIFormat = toolToOpenAIFormat;
1912
+ exports.zodObjectToInputSchema = zodObjectToInputSchema;
1913
+ exports.zodToJsonSchema = zodToJsonSchema;
1914
+ //# sourceMappingURL=chunk-2ZCWVAAK.cjs.map
1915
+ //# sourceMappingURL=chunk-2ZCWVAAK.cjs.map