libretto 0.3.0 → 0.3.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.
Files changed (162) hide show
  1. package/README.md +41 -125
  2. package/dist/cli/cli.js +298 -0
  3. package/dist/cli/commands/ai.js +21 -0
  4. package/dist/cli/commands/browser.js +82 -0
  5. package/dist/cli/commands/execution.js +490 -0
  6. package/dist/cli/commands/init.js +166 -0
  7. package/dist/cli/commands/logs.js +93 -0
  8. package/dist/cli/commands/snapshot.js +106 -0
  9. package/dist/cli/core/ai-config.js +149 -0
  10. package/dist/cli/core/browser.js +652 -0
  11. package/dist/cli/core/context.js +117 -0
  12. package/dist/cli/core/pause-signals.js +29 -0
  13. package/dist/cli/core/session-telemetry.js +491 -0
  14. package/dist/cli/core/session.js +183 -0
  15. package/dist/cli/core/snapshot-analyzer.js +492 -0
  16. package/dist/cli/core/telemetry.js +362 -0
  17. package/dist/cli/index.js +13 -0
  18. package/dist/cli/workers/run-integration-runtime.js +234 -0
  19. package/dist/cli/workers/run-integration-worker-protocol.js +12 -0
  20. package/dist/cli/workers/run-integration-worker.js +67 -0
  21. package/dist/index.cjs +144 -0
  22. package/dist/index.d.cts +21 -0
  23. package/dist/index.d.ts +21 -0
  24. package/dist/index.js +114 -0
  25. package/dist/runtime/download/download.cjs +70 -0
  26. package/dist/runtime/download/download.d.cts +35 -0
  27. package/dist/runtime/download/download.d.ts +35 -0
  28. package/dist/runtime/download/download.js +45 -0
  29. package/dist/runtime/download/index.cjs +30 -0
  30. package/dist/runtime/download/index.d.cts +3 -0
  31. package/dist/runtime/download/index.d.ts +3 -0
  32. package/dist/runtime/download/index.js +8 -0
  33. package/dist/runtime/extract/extract.cjs +88 -0
  34. package/dist/runtime/extract/extract.d.cts +23 -0
  35. package/dist/runtime/extract/extract.d.ts +23 -0
  36. package/dist/runtime/extract/extract.js +64 -0
  37. package/dist/runtime/extract/index.cjs +28 -0
  38. package/dist/runtime/extract/index.d.cts +5 -0
  39. package/dist/runtime/extract/index.d.ts +5 -0
  40. package/dist/runtime/extract/index.js +4 -0
  41. package/dist/runtime/network/index.cjs +28 -0
  42. package/dist/runtime/network/index.d.cts +4 -0
  43. package/dist/runtime/network/index.d.ts +4 -0
  44. package/dist/runtime/network/index.js +6 -0
  45. package/dist/runtime/network/network.cjs +91 -0
  46. package/dist/runtime/network/network.d.cts +28 -0
  47. package/dist/runtime/network/network.d.ts +28 -0
  48. package/dist/runtime/network/network.js +67 -0
  49. package/dist/runtime/recovery/agent.cjs +223 -0
  50. package/dist/runtime/recovery/agent.d.cts +13 -0
  51. package/dist/runtime/recovery/agent.d.ts +13 -0
  52. package/dist/runtime/recovery/agent.js +199 -0
  53. package/dist/runtime/recovery/errors.cjs +124 -0
  54. package/dist/runtime/recovery/errors.d.cts +31 -0
  55. package/dist/runtime/recovery/errors.d.ts +31 -0
  56. package/dist/runtime/recovery/errors.js +100 -0
  57. package/dist/runtime/recovery/index.cjs +34 -0
  58. package/dist/runtime/recovery/index.d.cts +7 -0
  59. package/dist/runtime/recovery/index.d.ts +7 -0
  60. package/dist/runtime/recovery/index.js +10 -0
  61. package/dist/runtime/recovery/recovery.cjs +55 -0
  62. package/dist/runtime/recovery/recovery.d.cts +12 -0
  63. package/dist/runtime/recovery/recovery.d.ts +12 -0
  64. package/dist/runtime/recovery/recovery.js +31 -0
  65. package/dist/shared/config/config.cjs +44 -0
  66. package/dist/shared/config/config.d.cts +10 -0
  67. package/dist/shared/config/config.d.ts +10 -0
  68. package/dist/shared/config/config.js +18 -0
  69. package/dist/shared/config/index.cjs +32 -0
  70. package/dist/shared/config/index.d.cts +1 -0
  71. package/dist/shared/config/index.d.ts +1 -0
  72. package/dist/shared/config/index.js +10 -0
  73. package/dist/shared/debug/index.cjs +30 -0
  74. package/dist/shared/debug/index.d.cts +1 -0
  75. package/dist/shared/debug/index.d.ts +1 -0
  76. package/dist/shared/debug/index.js +5 -0
  77. package/dist/shared/debug/pause.cjs +90 -0
  78. package/dist/shared/debug/pause.d.cts +16 -0
  79. package/dist/shared/debug/pause.d.ts +16 -0
  80. package/dist/shared/debug/pause.js +55 -0
  81. package/dist/shared/instrumentation/errors.cjs +81 -0
  82. package/dist/shared/instrumentation/errors.d.cts +12 -0
  83. package/dist/shared/instrumentation/errors.d.ts +12 -0
  84. package/dist/shared/instrumentation/errors.js +57 -0
  85. package/dist/shared/instrumentation/index.cjs +35 -0
  86. package/dist/shared/instrumentation/index.d.cts +6 -0
  87. package/dist/shared/instrumentation/index.d.ts +6 -0
  88. package/dist/shared/instrumentation/index.js +12 -0
  89. package/dist/shared/instrumentation/instrument.cjs +206 -0
  90. package/dist/shared/instrumentation/instrument.d.cts +32 -0
  91. package/dist/shared/instrumentation/instrument.d.ts +32 -0
  92. package/dist/shared/instrumentation/instrument.js +190 -0
  93. package/dist/shared/llm/ai-sdk-adapter.cjs +67 -0
  94. package/dist/shared/llm/ai-sdk-adapter.d.cts +22 -0
  95. package/dist/shared/llm/ai-sdk-adapter.d.ts +22 -0
  96. package/dist/shared/llm/ai-sdk-adapter.js +43 -0
  97. package/dist/shared/llm/client.cjs +139 -0
  98. package/dist/shared/llm/client.d.cts +6 -0
  99. package/dist/shared/llm/client.d.ts +6 -0
  100. package/dist/shared/llm/client.js +115 -0
  101. package/dist/shared/llm/index.cjs +31 -0
  102. package/dist/shared/llm/index.d.cts +5 -0
  103. package/dist/shared/llm/index.d.ts +5 -0
  104. package/dist/shared/llm/index.js +6 -0
  105. package/dist/shared/llm/types.cjs +16 -0
  106. package/dist/shared/llm/types.d.cts +66 -0
  107. package/dist/shared/llm/types.d.ts +66 -0
  108. package/dist/shared/llm/types.js +0 -0
  109. package/dist/shared/logger/index.cjs +37 -0
  110. package/dist/shared/logger/index.d.cts +2 -0
  111. package/dist/shared/logger/index.d.ts +2 -0
  112. package/dist/shared/logger/index.js +13 -0
  113. package/dist/shared/logger/logger.cjs +232 -0
  114. package/dist/shared/logger/logger.d.cts +86 -0
  115. package/dist/shared/logger/logger.d.ts +86 -0
  116. package/dist/shared/logger/logger.js +207 -0
  117. package/dist/shared/logger/sinks.cjs +160 -0
  118. package/dist/shared/logger/sinks.d.cts +9 -0
  119. package/dist/shared/logger/sinks.d.ts +9 -0
  120. package/dist/shared/logger/sinks.js +124 -0
  121. package/dist/shared/paths/paths.cjs +104 -0
  122. package/dist/shared/paths/paths.d.cts +10 -0
  123. package/dist/shared/paths/paths.d.ts +10 -0
  124. package/dist/shared/paths/paths.js +73 -0
  125. package/dist/shared/run/api.cjs +28 -0
  126. package/dist/shared/run/api.d.cts +2 -0
  127. package/dist/shared/run/api.d.ts +2 -0
  128. package/dist/shared/run/api.js +4 -0
  129. package/dist/shared/run/browser.cjs +98 -0
  130. package/dist/shared/run/browser.d.cts +22 -0
  131. package/dist/shared/run/browser.d.ts +22 -0
  132. package/dist/shared/run/browser.js +74 -0
  133. package/dist/shared/state/index.cjs +38 -0
  134. package/dist/shared/state/index.d.cts +2 -0
  135. package/dist/shared/state/index.d.ts +2 -0
  136. package/dist/shared/state/index.js +16 -0
  137. package/dist/shared/state/session-state.cjs +85 -0
  138. package/dist/shared/state/session-state.d.cts +34 -0
  139. package/dist/shared/state/session-state.d.ts +34 -0
  140. package/dist/shared/state/session-state.js +56 -0
  141. package/dist/shared/visualization/ghost-cursor.cjs +174 -0
  142. package/dist/shared/visualization/ghost-cursor.d.cts +37 -0
  143. package/dist/shared/visualization/ghost-cursor.d.ts +37 -0
  144. package/dist/shared/visualization/ghost-cursor.js +145 -0
  145. package/dist/shared/visualization/highlight.cjs +134 -0
  146. package/dist/shared/visualization/highlight.d.cts +22 -0
  147. package/dist/shared/visualization/highlight.d.ts +22 -0
  148. package/dist/shared/visualization/highlight.js +108 -0
  149. package/dist/shared/visualization/index.cjs +45 -0
  150. package/dist/shared/visualization/index.d.cts +3 -0
  151. package/dist/shared/visualization/index.d.ts +3 -0
  152. package/dist/shared/visualization/index.js +24 -0
  153. package/dist/shared/workflow/workflow.cjs +47 -0
  154. package/dist/shared/workflow/workflow.d.cts +21 -0
  155. package/dist/shared/workflow/workflow.d.ts +21 -0
  156. package/dist/shared/workflow/workflow.js +21 -0
  157. package/package.json +11 -70
  158. package/bin/libretto.mjs +0 -18
  159. package/scripts/postinstall.mjs +0 -48
  160. /package/{skill → .agents/skills/libretto}/SKILL.md +0 -0
  161. /package/{skill → .agents/skills/libretto}/code-generation-rules.md +0 -0
  162. /package/{skill → .agents/skills/libretto}/integration-approach-selection.md +0 -0
@@ -0,0 +1,23 @@
1
+ import { Page } from 'playwright';
2
+ import z from 'zod';
3
+ import { MinimalLogger } from '../../shared/logger/logger.js';
4
+ import { LLMClient } from '../../shared/llm/types.js';
5
+
6
+ type ExtractOptions<T extends z.ZodType> = {
7
+ page: Page;
8
+ instruction: string;
9
+ schema: T;
10
+ llmClient: LLMClient;
11
+ logger?: MinimalLogger;
12
+ /** Optional CSS selector to scope extraction to a specific element. */
13
+ selector?: string;
14
+ };
15
+ /**
16
+ * Generic AI-powered data extraction from page elements.
17
+ * Takes a screenshot (full-page via CDP or scoped to an element),
18
+ * captures DOM content, and uses an LLM to extract structured data
19
+ * matching the provided Zod schema.
20
+ */
21
+ declare function extractFromPage<T extends z.ZodType>(options: ExtractOptions<T>): Promise<z.infer<T>>;
22
+
23
+ export { type ExtractOptions, extractFromPage };
@@ -0,0 +1,64 @@
1
+ import { defaultLogger } from "../../shared/logger/logger.js";
2
+ async function extractFromPage(options) {
3
+ const { page, instruction, schema, selector, logger = defaultLogger, llmClient } = options;
4
+ let screenshot;
5
+ let domContent;
6
+ if (selector) {
7
+ const element = page.locator(selector);
8
+ await element.waitFor({ state: "visible", timeout: 1e4 });
9
+ const screenshotBuffer = await element.screenshot();
10
+ screenshot = screenshotBuffer.toString("base64");
11
+ try {
12
+ domContent = await element.innerHTML();
13
+ if (domContent.length > 3e4) {
14
+ domContent = domContent.slice(0, 3e4) + "\n... [truncated]";
15
+ }
16
+ } catch {
17
+ domContent = void 0;
18
+ }
19
+ } else {
20
+ const cdpClient = await page.context().newCDPSession(page);
21
+ await cdpClient.send("Page.enable");
22
+ const { data } = await cdpClient.send("Page.captureScreenshot", {
23
+ format: "png"
24
+ });
25
+ screenshot = data;
26
+ try {
27
+ const htmlContent = await page.content();
28
+ domContent = htmlContent.length > 5e4 ? htmlContent.slice(0, 5e4) + "\n... [truncated]" : htmlContent;
29
+ } catch {
30
+ domContent = void 0;
31
+ }
32
+ }
33
+ const prompt = `You are analyzing a screenshot${selector ? " of a specific element" : ""} from a web page to extract structured data.
34
+
35
+ Instruction: ${instruction}
36
+
37
+ ${domContent ? `Here is the HTML content for additional context:
38
+ <html>
39
+ ${domContent}
40
+ </html>` : ""}
41
+
42
+ Extract the requested information from the screenshot and return it in the specified format. Be precise and only extract what is visible.`;
43
+ const result = await llmClient.generateObjectFromMessages({
44
+ schema,
45
+ messages: [
46
+ {
47
+ role: "user",
48
+ content: [
49
+ { type: "text", text: prompt },
50
+ { type: "image", image: `data:image/png;base64,${screenshot}` }
51
+ ]
52
+ }
53
+ ],
54
+ temperature: 0
55
+ });
56
+ logger.info("extractFromPage completed", {
57
+ selector,
58
+ instruction: instruction.slice(0, 100)
59
+ });
60
+ return result;
61
+ }
62
+ export {
63
+ extractFromPage
64
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var extract_exports = {};
20
+ __export(extract_exports, {
21
+ extractFromPage: () => import_extract.extractFromPage
22
+ });
23
+ module.exports = __toCommonJS(extract_exports);
24
+ var import_extract = require("./extract.js");
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ extractFromPage
28
+ });
@@ -0,0 +1,5 @@
1
+ export { ExtractOptions, extractFromPage } from './extract.cjs';
2
+ import 'playwright';
3
+ import 'zod';
4
+ import '../../shared/logger/logger.cjs';
5
+ import '../../shared/llm/types.cjs';
@@ -0,0 +1,5 @@
1
+ export { ExtractOptions, extractFromPage } from './extract.js';
2
+ import 'playwright';
3
+ import 'zod';
4
+ import '../../shared/logger/logger.js';
5
+ import '../../shared/llm/types.js';
@@ -0,0 +1,4 @@
1
+ import { extractFromPage } from "./extract.js";
2
+ export {
3
+ extractFromPage
4
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var network_exports = {};
20
+ __export(network_exports, {
21
+ pageRequest: () => import_network.pageRequest
22
+ });
23
+ module.exports = __toCommonJS(network_exports);
24
+ var import_network = require("./network.js");
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ pageRequest
28
+ });
@@ -0,0 +1,4 @@
1
+ export { PageRequestOptions, RequestConfig, pageRequest } from './network.cjs';
2
+ import 'playwright';
3
+ import 'zod';
4
+ import '../../shared/logger/logger.cjs';
@@ -0,0 +1,4 @@
1
+ export { PageRequestOptions, RequestConfig, pageRequest } from './network.js';
2
+ import 'playwright';
3
+ import 'zod';
4
+ import '../../shared/logger/logger.js';
@@ -0,0 +1,6 @@
1
+ import {
2
+ pageRequest
3
+ } from "./network.js";
4
+ export {
5
+ pageRequest
6
+ };
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var network_exports = {};
20
+ __export(network_exports, {
21
+ pageRequest: () => pageRequest
22
+ });
23
+ module.exports = __toCommonJS(network_exports);
24
+ async function pageRequest(page, config, options) {
25
+ const { url, method = "GET", headers = {}, body, bodyType = "json", responseType = "json" } = config;
26
+ const { logger, schema } = options ?? {};
27
+ const startTime = Date.now();
28
+ const fetchHeaders = { ...headers };
29
+ let fetchBody;
30
+ if (body !== void 0) {
31
+ if (bodyType === "form") {
32
+ fetchHeaders["Content-Type"] = "application/x-www-form-urlencoded";
33
+ if (typeof body === "string") {
34
+ fetchBody = body;
35
+ } else {
36
+ fetchBody = new URLSearchParams(
37
+ Object.entries(body).map(([k, v]) => [k, String(v)])
38
+ ).toString();
39
+ }
40
+ } else {
41
+ fetchHeaders["Content-Type"] = "application/json";
42
+ fetchBody = typeof body === "string" ? body : JSON.stringify(body);
43
+ }
44
+ }
45
+ const result = await page.evaluate(
46
+ async ({ url: url2, method: method2, headers: headers2, body: body2, responseType: responseType2 }) => {
47
+ const res = await fetch(url2, {
48
+ method: method2,
49
+ headers: headers2,
50
+ body: body2 ?? void 0
51
+ });
52
+ const status = res.status;
53
+ const ok = res.ok;
54
+ let data;
55
+ if (responseType2 === "json") {
56
+ data = await res.json();
57
+ } else {
58
+ data = await res.text();
59
+ }
60
+ return { status, ok, data };
61
+ },
62
+ { url, method, headers: fetchHeaders, body: fetchBody, responseType }
63
+ );
64
+ const duration = Date.now() - startTime;
65
+ if (!result.ok) {
66
+ logger?.warn("network:request:error", {
67
+ method,
68
+ url,
69
+ status: result.status,
70
+ duration,
71
+ body: typeof result.data === "string" ? result.data.slice(0, 500) : void 0
72
+ });
73
+ throw new Error(
74
+ `pageRequest failed: ${method} ${url} returned ${result.status}`
75
+ );
76
+ }
77
+ logger?.info("network:request", {
78
+ method,
79
+ url,
80
+ status: result.status,
81
+ duration
82
+ });
83
+ if (schema) {
84
+ return schema.parse(result.data);
85
+ }
86
+ return result.data;
87
+ }
88
+ // Annotate the CommonJS export names for ESM import in node:
89
+ 0 && (module.exports = {
90
+ pageRequest
91
+ });
@@ -0,0 +1,28 @@
1
+ import { Page } from 'playwright';
2
+ import z from 'zod';
3
+ import { MinimalLogger } from '../../shared/logger/logger.cjs';
4
+
5
+ type RequestConfig = {
6
+ url: string;
7
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
8
+ headers?: Record<string, string>;
9
+ body?: Record<string, any> | string;
10
+ /** How to serialize the body. Defaults to "json". */
11
+ bodyType?: "json" | "form";
12
+ /** How to parse the response. Defaults to "json". */
13
+ responseType?: "json" | "text" | "xml";
14
+ };
15
+ type PageRequestOptions<T extends z.ZodType | undefined = undefined> = {
16
+ logger?: MinimalLogger;
17
+ /** Optional Zod schema to validate the response body. */
18
+ schema?: T;
19
+ };
20
+ type PageRequestResult<T extends z.ZodType | undefined> = T extends z.ZodType ? z.infer<T> : any;
21
+ /**
22
+ * Executes a fetch() call inside the browser context via page.evaluate().
23
+ * Provides typed request config, automatic response parsing, optional Zod
24
+ * validation, and logging.
25
+ */
26
+ declare function pageRequest<T extends z.ZodType | undefined = undefined>(page: Page, config: RequestConfig, options?: PageRequestOptions<T>): Promise<PageRequestResult<T>>;
27
+
28
+ export { type PageRequestOptions, type RequestConfig, pageRequest };
@@ -0,0 +1,28 @@
1
+ import { Page } from 'playwright';
2
+ import z from 'zod';
3
+ import { MinimalLogger } from '../../shared/logger/logger.js';
4
+
5
+ type RequestConfig = {
6
+ url: string;
7
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
8
+ headers?: Record<string, string>;
9
+ body?: Record<string, any> | string;
10
+ /** How to serialize the body. Defaults to "json". */
11
+ bodyType?: "json" | "form";
12
+ /** How to parse the response. Defaults to "json". */
13
+ responseType?: "json" | "text" | "xml";
14
+ };
15
+ type PageRequestOptions<T extends z.ZodType | undefined = undefined> = {
16
+ logger?: MinimalLogger;
17
+ /** Optional Zod schema to validate the response body. */
18
+ schema?: T;
19
+ };
20
+ type PageRequestResult<T extends z.ZodType | undefined> = T extends z.ZodType ? z.infer<T> : any;
21
+ /**
22
+ * Executes a fetch() call inside the browser context via page.evaluate().
23
+ * Provides typed request config, automatic response parsing, optional Zod
24
+ * validation, and logging.
25
+ */
26
+ declare function pageRequest<T extends z.ZodType | undefined = undefined>(page: Page, config: RequestConfig, options?: PageRequestOptions<T>): Promise<PageRequestResult<T>>;
27
+
28
+ export { type PageRequestOptions, type RequestConfig, pageRequest };
@@ -0,0 +1,67 @@
1
+ async function pageRequest(page, config, options) {
2
+ const { url, method = "GET", headers = {}, body, bodyType = "json", responseType = "json" } = config;
3
+ const { logger, schema } = options ?? {};
4
+ const startTime = Date.now();
5
+ const fetchHeaders = { ...headers };
6
+ let fetchBody;
7
+ if (body !== void 0) {
8
+ if (bodyType === "form") {
9
+ fetchHeaders["Content-Type"] = "application/x-www-form-urlencoded";
10
+ if (typeof body === "string") {
11
+ fetchBody = body;
12
+ } else {
13
+ fetchBody = new URLSearchParams(
14
+ Object.entries(body).map(([k, v]) => [k, String(v)])
15
+ ).toString();
16
+ }
17
+ } else {
18
+ fetchHeaders["Content-Type"] = "application/json";
19
+ fetchBody = typeof body === "string" ? body : JSON.stringify(body);
20
+ }
21
+ }
22
+ const result = await page.evaluate(
23
+ async ({ url: url2, method: method2, headers: headers2, body: body2, responseType: responseType2 }) => {
24
+ const res = await fetch(url2, {
25
+ method: method2,
26
+ headers: headers2,
27
+ body: body2 ?? void 0
28
+ });
29
+ const status = res.status;
30
+ const ok = res.ok;
31
+ let data;
32
+ if (responseType2 === "json") {
33
+ data = await res.json();
34
+ } else {
35
+ data = await res.text();
36
+ }
37
+ return { status, ok, data };
38
+ },
39
+ { url, method, headers: fetchHeaders, body: fetchBody, responseType }
40
+ );
41
+ const duration = Date.now() - startTime;
42
+ if (!result.ok) {
43
+ logger?.warn("network:request:error", {
44
+ method,
45
+ url,
46
+ status: result.status,
47
+ duration,
48
+ body: typeof result.data === "string" ? result.data.slice(0, 500) : void 0
49
+ });
50
+ throw new Error(
51
+ `pageRequest failed: ${method} ${url} returned ${result.status}`
52
+ );
53
+ }
54
+ logger?.info("network:request", {
55
+ method,
56
+ url,
57
+ status: result.status,
58
+ duration
59
+ });
60
+ if (schema) {
61
+ return schema.parse(result.data);
62
+ }
63
+ return result.data;
64
+ }
65
+ export {
66
+ pageRequest
67
+ };
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var agent_exports = {};
20
+ __export(agent_exports, {
21
+ executeRecoveryAgent: () => executeRecoveryAgent
22
+ });
23
+ module.exports = __toCommonJS(agent_exports);
24
+ var import_logger = require("../../shared/logger/logger.js");
25
+ var import_zod = require("zod");
26
+ function delay(ms) {
27
+ return new Promise((resolve) => setTimeout(resolve, ms));
28
+ }
29
+ const KEY_MAPPINGS = {
30
+ ENTER: "Enter",
31
+ RETURN: "Enter",
32
+ TAB: "Tab",
33
+ SPACE: " ",
34
+ BACKSPACE: "Backspace",
35
+ DELETE: "Delete",
36
+ ESCAPE: "Escape",
37
+ ESC: "Escape",
38
+ UP: "ArrowUp",
39
+ DOWN: "ArrowDown",
40
+ LEFT: "ArrowLeft",
41
+ RIGHT: "ArrowRight",
42
+ HOME: "Home",
43
+ END: "End",
44
+ PAGEUP: "PageUp",
45
+ PAGEDOWN: "PageDown",
46
+ CTRL: "Control",
47
+ CONTROL: "Control",
48
+ ALT: "Alt",
49
+ SHIFT: "Shift",
50
+ META: "Meta",
51
+ CMD: "Meta",
52
+ COMMAND: "Meta"
53
+ };
54
+ function mapKeyName(key) {
55
+ return KEY_MAPPINGS[key.toUpperCase()] ?? key;
56
+ }
57
+ async function executeBrowserAction(page, action, logger = import_logger.defaultLogger) {
58
+ switch (action.type) {
59
+ case "click": {
60
+ const { x, y, button = "left" } = action;
61
+ const playwrightButton = button === "wheel" || button === "back" || button === "forward" ? "left" : button;
62
+ await page.mouse.click(x, y, { button: playwrightButton });
63
+ logger.info(`Clicked at (${x}, ${y}) with ${button} button`);
64
+ break;
65
+ }
66
+ case "double_click": {
67
+ const { x, y } = action;
68
+ await page.mouse.dblclick(x, y);
69
+ logger.info(`Double-clicked at (${x}, ${y})`);
70
+ break;
71
+ }
72
+ case "scroll": {
73
+ const { x, y, scroll_x, scroll_y } = action;
74
+ await page.mouse.move(x, y);
75
+ await page.evaluate(`window.scrollBy(${scroll_x}, ${scroll_y})`);
76
+ logger.info(`Scrolled at (${x}, ${y}) by (${scroll_x}, ${scroll_y})`);
77
+ break;
78
+ }
79
+ case "keypress": {
80
+ for (const key of action.keys) {
81
+ const mapped = mapKeyName(key);
82
+ await page.keyboard.press(mapped);
83
+ logger.info(`Pressed key: ${key} (mapped to ${mapped})`);
84
+ }
85
+ break;
86
+ }
87
+ case "type": {
88
+ await page.keyboard.type(action.text);
89
+ logger.info(`Typed text: ${action.text}`);
90
+ break;
91
+ }
92
+ case "wait": {
93
+ await delay(2e3);
94
+ logger.info("Waited 2 seconds");
95
+ break;
96
+ }
97
+ case "screenshot": {
98
+ logger.info("Screenshot action (no-op, taken automatically)");
99
+ break;
100
+ }
101
+ case "drag": {
102
+ const { path } = action;
103
+ const start = path[0];
104
+ const end = path[path.length - 1];
105
+ if (path.length >= 2 && start && end) {
106
+ await page.mouse.move(start.x, start.y);
107
+ await page.mouse.down();
108
+ for (let i = 1; i < path.length; i++) {
109
+ const point = path[i];
110
+ if (point) await page.mouse.move(point.x, point.y);
111
+ }
112
+ await page.mouse.up();
113
+ logger.info(`Dragged from (${start.x}, ${start.y}) to (${end.x}, ${end.y})`);
114
+ }
115
+ break;
116
+ }
117
+ case "move": {
118
+ const { x, y } = action;
119
+ await page.mouse.move(x, y);
120
+ logger.info(`Moved mouse to (${x}, ${y})`);
121
+ break;
122
+ }
123
+ case "done": {
124
+ break;
125
+ }
126
+ }
127
+ }
128
+ const recoveryActionSchema = import_zod.z.object({
129
+ reasoning: import_zod.z.string().describe("Your reasoning about what you see and what action to take"),
130
+ action: import_zod.z.discriminatedUnion("type", [
131
+ import_zod.z.object({
132
+ type: import_zod.z.literal("click"),
133
+ x: import_zod.z.number(),
134
+ y: import_zod.z.number()
135
+ }),
136
+ import_zod.z.object({
137
+ type: import_zod.z.literal("type"),
138
+ text: import_zod.z.string()
139
+ }),
140
+ import_zod.z.object({
141
+ type: import_zod.z.literal("keypress"),
142
+ keys: import_zod.z.array(import_zod.z.string())
143
+ }),
144
+ import_zod.z.object({
145
+ type: import_zod.z.literal("scroll"),
146
+ x: import_zod.z.number(),
147
+ y: import_zod.z.number(),
148
+ scroll_x: import_zod.z.number(),
149
+ scroll_y: import_zod.z.number()
150
+ }),
151
+ import_zod.z.object({
152
+ type: import_zod.z.literal("wait")
153
+ }),
154
+ import_zod.z.object({
155
+ type: import_zod.z.literal("done")
156
+ })
157
+ ])
158
+ });
159
+ async function executeRecoveryAgent(page, instruction, logger, llmClient) {
160
+ if (!llmClient) {
161
+ return;
162
+ }
163
+ const log = logger ?? import_logger.defaultLogger;
164
+ log.info("Executing vision-based recovery agent", { instruction });
165
+ const viewport = page.viewportSize();
166
+ if (!viewport) {
167
+ throw new Error("Viewport size not found");
168
+ }
169
+ let screenshot;
170
+ try {
171
+ screenshot = (await page.screenshot({ fullPage: false, timeout: 1e4 })).toString("base64");
172
+ } catch (screenshotError) {
173
+ log.warn("Failed to take screenshot for recovery agent, skipping", {
174
+ screenshotError: screenshotError instanceof Error ? screenshotError.message : String(screenshotError)
175
+ });
176
+ throw new Error("Failed to take screenshot for recovery agent");
177
+ }
178
+ const maxSteps = 3;
179
+ for (let step = 1; step <= maxSteps; step++) {
180
+ const result = await llmClient.generateObjectFromMessages({
181
+ schema: recoveryActionSchema,
182
+ messages: [
183
+ {
184
+ role: "user",
185
+ content: [
186
+ {
187
+ type: "text",
188
+ text: `You are an expert browser support agent. Your job is to resolve issues when browser automation encounters unexpected website behavior (e.g., popups blocking interaction).
189
+
190
+ Your task: ${instruction}
191
+
192
+ Viewport: ${viewport.width}x${viewport.height}px. Complete this in as few steps as possible.
193
+ Analyze the screenshot and decide what action to take. If the task is complete or no action is needed, use the "done" action type.`
194
+ },
195
+ {
196
+ type: "image",
197
+ image: `data:image/png;base64,${screenshot}`
198
+ }
199
+ ]
200
+ }
201
+ ],
202
+ temperature: 0
203
+ });
204
+ log.info(`Recovery step ${step}/${maxSteps}`, {
205
+ reasoning: result.reasoning,
206
+ action: result.action
207
+ });
208
+ if (result.action.type === "done") {
209
+ log.info("Recovery agent completed - no more actions needed");
210
+ break;
211
+ }
212
+ await executeBrowserAction(page, result.action, log);
213
+ await delay(2e3);
214
+ screenshot = (await page.screenshot({ fullPage: false })).toString(
215
+ "base64"
216
+ );
217
+ }
218
+ log.info("Recovery agent execution completed");
219
+ }
220
+ // Annotate the CommonJS export names for ESM import in node:
221
+ 0 && (module.exports = {
222
+ executeRecoveryAgent
223
+ });
@@ -0,0 +1,13 @@
1
+ import { Page } from 'playwright';
2
+ import { MinimalLogger } from '../../shared/logger/logger.cjs';
3
+ import { LLMClient } from '../../shared/llm/types.cjs';
4
+ import 'zod';
5
+
6
+ /**
7
+ * Executes a vision-based recovery agent to recover from browser automation failures.
8
+ * Takes a screenshot, sends it to the LLM with the instruction, and executes
9
+ * the LLM's suggested browser actions.
10
+ */
11
+ declare function executeRecoveryAgent(page: Page, instruction: string, logger?: MinimalLogger, llmClient?: LLMClient): Promise<void>;
12
+
13
+ export { executeRecoveryAgent };
@@ -0,0 +1,13 @@
1
+ import { Page } from 'playwright';
2
+ import { MinimalLogger } from '../../shared/logger/logger.js';
3
+ import { LLMClient } from '../../shared/llm/types.js';
4
+ import 'zod';
5
+
6
+ /**
7
+ * Executes a vision-based recovery agent to recover from browser automation failures.
8
+ * Takes a screenshot, sends it to the LLM with the instruction, and executes
9
+ * the LLM's suggested browser actions.
10
+ */
11
+ declare function executeRecoveryAgent(page: Page, instruction: string, logger?: MinimalLogger, llmClient?: LLMClient): Promise<void>;
12
+
13
+ export { executeRecoveryAgent };