ScuttleBot

scuttlebot / tests / e2e / node_modules / playwright / lib / mcp / browser / response.js
Blame History Raw 279 lines
1
"use strict";
2
var __create = Object.create;
3
var __defProp = Object.defineProperty;
4
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
var __getOwnPropNames = Object.getOwnPropertyNames;
6
var __getProtoOf = Object.getPrototypeOf;
7
var __hasOwnProp = Object.prototype.hasOwnProperty;
8
var __export = (target, all) => {
9
for (var name in all)
10
__defProp(target, name, { get: all[name], enumerable: true });
11
};
12
var __copyProps = (to, from, except, desc) => {
13
if (from && typeof from === "object" || typeof from === "function") {
14
for (let key of __getOwnPropNames(from))
15
if (!__hasOwnProp.call(to, key) && key !== except)
16
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
}
18
return to;
19
};
20
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
// If the importer is in node compatibility mode or this is not an ESM
22
// file that has been converted to a CommonJS file using a Babel-
23
// compatible transform (i.e. "__esModule" has not been set), then set
24
// "default" to the CommonJS "module.exports" for node compatibility.
25
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
mod
27
));
28
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
var response_exports = {};
30
__export(response_exports, {
31
Response: () => Response,
32
parseResponse: () => parseResponse,
33
renderTabMarkdown: () => renderTabMarkdown,
34
renderTabsMarkdown: () => renderTabsMarkdown,
35
requestDebug: () => requestDebug
36
});
37
module.exports = __toCommonJS(response_exports);
38
var import_fs = __toESM(require("fs"));
39
var import_path = __toESM(require("path"));
40
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
41
var import_tab = require("./tab");
42
var import_utils = require("./tools/utils");
43
const requestDebug = (0, import_utilsBundle.debug)("pw:mcp:request");
44
class Response {
45
constructor(ordinal, context, toolName, toolArgs) {
46
this._results = [];
47
this._errors = [];
48
this._code = [];
49
this._images = [];
50
this._includeSnapshot = "none";
51
this._ordinal = ordinal;
52
this._context = context;
53
this.toolName = toolName;
54
this.toolArgs = toolArgs;
55
}
56
static {
57
this._ordinal = 0;
58
}
59
static create(context, toolName, toolArgs) {
60
return new Response(++Response._ordinal, context, toolName, toolArgs);
61
}
62
addTextResult(result) {
63
this._results.push({ text: result });
64
}
65
async addResult(result) {
66
if (result.data && !result.suggestedFilename)
67
result.suggestedFilename = (0, import_utils.dateAsFileName)(result.ext ?? "bin");
68
if (this._context.config.outputMode === "file") {
69
if (!result.suggestedFilename)
70
result.suggestedFilename = (0, import_utils.dateAsFileName)(result.ext ?? (result.text ? "txt" : "bin"));
71
}
72
const entry = { text: result.text, data: result.data, title: result.title };
73
if (result.suggestedFilename)
74
entry.filename = await this._context.outputFile(result.suggestedFilename, { origin: "llm", title: result.title ?? "Saved result" });
75
this._results.push(entry);
76
return { fileName: entry.filename };
77
}
78
addError(error) {
79
this._errors.push(error);
80
}
81
addCode(code) {
82
this._code.push(code);
83
}
84
addImage(image) {
85
this._images.push(image);
86
}
87
setIncludeSnapshot() {
88
this._includeSnapshot = this._context.config.snapshot.mode;
89
}
90
setIncludeFullSnapshot(includeSnapshotFileName) {
91
this._includeSnapshot = "full";
92
this._includeSnapshotFileName = includeSnapshotFileName;
93
}
94
async build() {
95
const rootPath = this._context.firstRootPath();
96
const sections = [];
97
const addSection = (title) => {
98
const section = { title, content: [] };
99
sections.push(section);
100
return section.content;
101
};
102
if (this._errors.length) {
103
const text = addSection("Error");
104
text.push("### Error");
105
text.push(this._errors.join("\n"));
106
}
107
if (this._results.length) {
108
const text = addSection("Result");
109
for (const result of this._results) {
110
if (result.filename) {
111
text.push(`- [${result.title}](${rootPath ? import_path.default.relative(rootPath, result.filename) : result.filename})`);
112
if (result.data)
113
await import_fs.default.promises.writeFile(result.filename, result.data);
114
else if (result.text)
115
await import_fs.default.promises.writeFile(result.filename, this._redactText(result.text));
116
} else if (result.text) {
117
text.push(result.text);
118
}
119
}
120
}
121
if (this._context.config.codegen !== "none" && this._code.length) {
122
const text = addSection("Ran Playwright code");
123
text.push(...this._code);
124
}
125
const tabSnapshot = this._context.currentTab() ? await this._context.currentTabOrDie().captureSnapshot() : void 0;
126
const tabHeaders = await Promise.all(this._context.tabs().map((tab) => tab.headerSnapshot()));
127
if (tabHeaders.some((header) => header.changed)) {
128
if (tabHeaders.length !== 1) {
129
const text2 = addSection("Open tabs");
130
text2.push(...renderTabsMarkdown(tabHeaders));
131
}
132
const text = addSection("Page");
133
text.push(...renderTabMarkdown(tabHeaders[0]));
134
}
135
if (tabSnapshot?.modalStates.length) {
136
const text = addSection("Modal state");
137
text.push(...(0, import_tab.renderModalStates)(tabSnapshot.modalStates));
138
}
139
if (tabSnapshot && this._includeSnapshot === "full") {
140
let fileName;
141
if (this._includeSnapshotFileName)
142
fileName = await this._context.outputFile(this._includeSnapshotFileName, { origin: "llm", title: "Saved snapshot" });
143
else if (this._context.config.outputMode === "file")
144
fileName = await this._context.outputFile(`snapshot-${this._ordinal}.yml`, { origin: "code", title: "Saved snapshot" });
145
if (fileName) {
146
await import_fs.default.promises.writeFile(fileName, tabSnapshot.ariaSnapshot);
147
const text = addSection("Snapshot");
148
text.push(`- File: ${rootPath ? import_path.default.relative(rootPath, fileName) : fileName}`);
149
} else {
150
const text = addSection("Snapshot");
151
text.push("```yaml");
152
text.push(tabSnapshot.ariaSnapshot);
153
text.push("```");
154
}
155
}
156
if (tabSnapshot && this._includeSnapshot === "incremental") {
157
const text = addSection("Snapshot");
158
text.push("```yaml");
159
if (tabSnapshot.ariaSnapshotDiff !== void 0)
160
text.push(tabSnapshot.ariaSnapshotDiff);
161
else
162
text.push(tabSnapshot.ariaSnapshot);
163
text.push("```");
164
}
165
if (tabSnapshot?.events.filter((event) => event.type !== "request").length) {
166
const text = addSection("Events");
167
for (const event of tabSnapshot.events) {
168
if (event.type === "console") {
169
if ((0, import_tab.shouldIncludeMessage)(this._context.config.console.level, event.message.type))
170
text.push(`- ${trimMiddle(event.message.toString(), 100)}`);
171
} else if (event.type === "download-start") {
172
text.push(`- Downloading file ${event.download.download.suggestedFilename()} ...`);
173
} else if (event.type === "download-finish") {
174
text.push(`- Downloaded file ${event.download.download.suggestedFilename()} to "${rootPath ? import_path.default.relative(rootPath, event.download.outputFile) : event.download.outputFile}"`);
175
}
176
}
177
}
178
const allText = sections.flatMap((section) => {
179
const content2 = [];
180
content2.push(`### ${section.title}`);
181
content2.push(...section.content);
182
content2.push("");
183
return content2;
184
}).join("\n");
185
const content = [
186
{
187
type: "text",
188
text: this._redactText(allText)
189
}
190
];
191
if (this._context.config.imageResponses !== "omit") {
192
for (const image of this._images)
193
content.push({ type: "image", data: image.data.toString("base64"), mimeType: image.contentType });
194
}
195
return {
196
content,
197
...this._errors.length > 0 ? { isError: true } : {}
198
};
199
}
200
_redactText(text) {
201
for (const [secretName, secretValue] of Object.entries(this._context.config.secrets ?? {}))
202
text = text.replaceAll(secretValue, `<secret>${secretName}</secret>`);
203
return text;
204
}
205
}
206
function renderTabMarkdown(tab) {
207
const lines = [`- Page URL: ${tab.url}`];
208
if (tab.title)
209
lines.push(`- Page Title: ${tab.title}`);
210
return lines;
211
}
212
function renderTabsMarkdown(tabs) {
213
if (!tabs.length)
214
return ['No open tabs. Use the "browser_navigate" tool to navigate to a page first.'];
215
const lines = [];
216
for (let i = 0; i < tabs.length; i++) {
217
const tab = tabs[i];
218
const current = tab.current ? " (current)" : "";
219
lines.push(`- ${i}:${current} [${tab.title}](${tab.url})`);
220
}
221
return lines;
222
}
223
function trimMiddle(text, maxLength) {
224
if (text.length <= maxLength)
225
return text;
226
return text.slice(0, Math.floor(maxLength / 2)) + "..." + text.slice(-3 - Math.floor(maxLength / 2));
227
}
228
function parseSections(text) {
229
const sections = /* @__PURE__ */ new Map();
230
const sectionHeaders = text.split(/^### /m).slice(1);
231
for (const section of sectionHeaders) {
232
const firstNewlineIndex = section.indexOf("\n");
233
if (firstNewlineIndex === -1)
234
continue;
235
const sectionName = section.substring(0, firstNewlineIndex);
236
const sectionContent = section.substring(firstNewlineIndex + 1).trim();
237
sections.set(sectionName, sectionContent);
238
}
239
return sections;
240
}
241
function parseResponse(response) {
242
if (response.content?.[0].type !== "text")
243
return void 0;
244
const text = response.content[0].text;
245
const sections = parseSections(text);
246
const error = sections.get("Error");
247
const result = sections.get("Result");
248
const code = sections.get("Ran Playwright code");
249
const tabs = sections.get("Open tabs");
250
const page = sections.get("Page");
251
const snapshot = sections.get("Snapshot");
252
const events = sections.get("Events");
253
const modalState = sections.get("Modal state");
254
const codeNoFrame = code?.replace(/^```js\n/, "").replace(/\n```$/, "");
255
const isError = response.isError;
256
const attachments = response.content.length > 1 ? response.content.slice(1) : void 0;
257
return {
258
result,
259
error,
260
code: codeNoFrame,
261
tabs,
262
page,
263
snapshot,
264
events,
265
modalState,
266
isError,
267
attachments,
268
text
269
};
270
}
271
// Annotate the CommonJS export names for ESM import in node:
272
0 && (module.exports = {
273
Response,
274
parseResponse,
275
renderTabMarkdown,
276
renderTabsMarkdown,
277
requestDebug
278
});
279

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button