|
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
|
|