response.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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 response_exports = {};
  20. __export(response_exports, {
  21. Response: () => Response,
  22. parseResponse: () => parseResponse,
  23. requestDebug: () => requestDebug
  24. });
  25. module.exports = __toCommonJS(response_exports);
  26. var import_utilsBundle = require("playwright-core/lib/utilsBundle");
  27. var import_tab = require("./tab");
  28. const requestDebug = (0, import_utilsBundle.debug)("pw:mcp:request");
  29. class Response {
  30. constructor(context, toolName, toolArgs) {
  31. this._result = [];
  32. this._code = [];
  33. this._images = [];
  34. this._includeSnapshot = "none";
  35. this._includeTabs = false;
  36. this._context = context;
  37. this.toolName = toolName;
  38. this.toolArgs = toolArgs;
  39. }
  40. addResult(result) {
  41. this._result.push(result);
  42. }
  43. addError(error) {
  44. this._result.push(error);
  45. this._isError = true;
  46. }
  47. isError() {
  48. return this._isError;
  49. }
  50. result() {
  51. return this._result.join("\n");
  52. }
  53. addCode(code) {
  54. this._code.push(code);
  55. }
  56. code() {
  57. return this._code.join("\n");
  58. }
  59. addImage(image) {
  60. this._images.push(image);
  61. }
  62. images() {
  63. return this._images;
  64. }
  65. setIncludeSnapshot(full) {
  66. this._includeSnapshot = full ?? "incremental";
  67. }
  68. setIncludeTabs() {
  69. this._includeTabs = true;
  70. }
  71. async finish() {
  72. if (this._includeSnapshot !== "none" && this._context.currentTab())
  73. this._tabSnapshot = await this._context.currentTabOrDie().captureSnapshot();
  74. for (const tab of this._context.tabs())
  75. await tab.updateTitle();
  76. }
  77. tabSnapshot() {
  78. return this._tabSnapshot;
  79. }
  80. logBegin() {
  81. if (requestDebug.enabled)
  82. requestDebug(this.toolName, this.toolArgs);
  83. }
  84. logEnd() {
  85. if (requestDebug.enabled)
  86. requestDebug(this.serialize({ omitSnapshot: true, omitBlobs: true }));
  87. }
  88. serialize(options = {}) {
  89. const response = [];
  90. if (this._result.length) {
  91. response.push("### Result");
  92. response.push(this._result.join("\n"));
  93. response.push("");
  94. }
  95. if (this._code.length) {
  96. response.push(`### Ran Playwright code
  97. \`\`\`js
  98. ${this._code.join("\n")}
  99. \`\`\``);
  100. response.push("");
  101. }
  102. if (this._includeSnapshot !== "none" || this._includeTabs)
  103. response.push(...renderTabsMarkdown(this._context.tabs(), this._includeTabs));
  104. if (this._tabSnapshot?.modalStates.length) {
  105. response.push(...(0, import_tab.renderModalStates)(this._context, this._tabSnapshot.modalStates));
  106. response.push("");
  107. } else if (this._tabSnapshot) {
  108. const includeSnapshot = options.omitSnapshot ? "none" : this._includeSnapshot;
  109. response.push(renderTabSnapshot(this._tabSnapshot, includeSnapshot));
  110. response.push("");
  111. }
  112. const content = [
  113. { type: "text", text: response.join("\n") }
  114. ];
  115. if (this._context.config.imageResponses !== "omit") {
  116. for (const image of this._images)
  117. content.push({ type: "image", data: options.omitBlobs ? "<blob>" : image.data.toString("base64"), mimeType: image.contentType });
  118. }
  119. this._redactSecrets(content);
  120. return { content, isError: this._isError };
  121. }
  122. _redactSecrets(content) {
  123. if (!this._context.config.secrets)
  124. return;
  125. for (const item of content) {
  126. if (item.type !== "text")
  127. continue;
  128. for (const [secretName, secretValue] of Object.entries(this._context.config.secrets))
  129. item.text = item.text.replaceAll(secretValue, `<secret>${secretName}</secret>`);
  130. }
  131. }
  132. }
  133. function renderTabSnapshot(tabSnapshot, includeSnapshot) {
  134. const lines = [];
  135. if (tabSnapshot.consoleMessages.length) {
  136. lines.push(`### New console messages`);
  137. for (const message of tabSnapshot.consoleMessages)
  138. lines.push(`- ${trim(message.toString(), 100)}`);
  139. lines.push("");
  140. }
  141. if (tabSnapshot.downloads.length) {
  142. lines.push(`### Downloads`);
  143. for (const entry of tabSnapshot.downloads) {
  144. if (entry.finished)
  145. lines.push(`- Downloaded file ${entry.download.suggestedFilename()} to ${entry.outputFile}`);
  146. else
  147. lines.push(`- Downloading file ${entry.download.suggestedFilename()} ...`);
  148. }
  149. lines.push("");
  150. }
  151. if (includeSnapshot === "incremental" && tabSnapshot.ariaSnapshotDiff === "") {
  152. return lines.join("\n");
  153. }
  154. lines.push(`### Page state`);
  155. lines.push(`- Page URL: ${tabSnapshot.url}`);
  156. lines.push(`- Page Title: ${tabSnapshot.title}`);
  157. if (includeSnapshot !== "none") {
  158. lines.push(`- Page Snapshot:`);
  159. lines.push("```yaml");
  160. if (includeSnapshot === "incremental" && tabSnapshot.ariaSnapshotDiff !== void 0)
  161. lines.push(tabSnapshot.ariaSnapshotDiff);
  162. else
  163. lines.push(tabSnapshot.ariaSnapshot);
  164. lines.push("```");
  165. }
  166. return lines.join("\n");
  167. }
  168. function renderTabsMarkdown(tabs, force = false) {
  169. if (tabs.length === 1 && !force)
  170. return [];
  171. if (!tabs.length) {
  172. return [
  173. "### Open tabs",
  174. 'No open tabs. Use the "browser_navigate" tool to navigate to a page first.',
  175. ""
  176. ];
  177. }
  178. const lines = ["### Open tabs"];
  179. for (let i = 0; i < tabs.length; i++) {
  180. const tab = tabs[i];
  181. const current = tab.isCurrentTab() ? " (current)" : "";
  182. lines.push(`- ${i}:${current} [${tab.lastTitle()}] (${tab.page.url()})`);
  183. }
  184. lines.push("");
  185. return lines;
  186. }
  187. function trim(text, maxLength) {
  188. if (text.length <= maxLength)
  189. return text;
  190. return text.slice(0, maxLength) + "...";
  191. }
  192. function parseSections(text) {
  193. const sections = /* @__PURE__ */ new Map();
  194. const sectionHeaders = text.split(/^### /m).slice(1);
  195. for (const section of sectionHeaders) {
  196. const firstNewlineIndex = section.indexOf("\n");
  197. if (firstNewlineIndex === -1)
  198. continue;
  199. const sectionName = section.substring(0, firstNewlineIndex);
  200. const sectionContent = section.substring(firstNewlineIndex + 1).trim();
  201. sections.set(sectionName, sectionContent);
  202. }
  203. return sections;
  204. }
  205. function parseResponse(response) {
  206. if (response.content?.[0].type !== "text")
  207. return void 0;
  208. const text = response.content[0].text;
  209. const sections = parseSections(text);
  210. const result = sections.get("Result");
  211. const code = sections.get("Ran Playwright code");
  212. const tabs = sections.get("Open tabs");
  213. const pageState = sections.get("Page state");
  214. const consoleMessages = sections.get("New console messages");
  215. const modalState = sections.get("Modal state");
  216. const downloads = sections.get("Downloads");
  217. const codeNoFrame = code?.replace(/^```js\n/, "").replace(/\n```$/, "");
  218. const isError = response.isError;
  219. const attachments = response.content.slice(1);
  220. return {
  221. result,
  222. code: codeNoFrame,
  223. tabs,
  224. pageState,
  225. consoleMessages,
  226. modalState,
  227. downloads,
  228. isError,
  229. attachments
  230. };
  231. }
  232. // Annotate the CommonJS export names for ESM import in node:
  233. 0 && (module.exports = {
  234. Response,
  235. parseResponse,
  236. requestDebug
  237. });