chrome-devtools-frontend 1.0.1605390 → 1.0.1606789
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.
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/platform/api/HostRuntime.ts +9 -6
- package/front_end/core/platform/browser/HostRuntime.ts +2 -2
- package/front_end/core/platform/node/HostRuntime.ts +7 -7
- package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/CrashReportContextModel.ts +28 -0
- package/front_end/core/sdk/sdk.ts +2 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +3 -3
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +5 -4
- package/front_end/entrypoints/main/MainImpl.ts +0 -101
- package/front_end/models/ai_assistance/ChangeManager.ts +6 -6
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +112 -5
- package/front_end/models/ai_assistance/agents/AiAgent.ts +0 -24
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +6 -3
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +13 -1
- package/front_end/models/ai_assistance/agents/FileAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +24 -15
- package/front_end/models/ai_assistance/ai_assistance.ts +0 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -5
- package/front_end/models/web_mcp/WebMCPModel.ts +187 -0
- package/front_end/models/web_mcp/web_mcp.ts +9 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -1
- package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
- package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +88 -0
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +19 -3
- package/front_end/panels/ai_assistance/components/ChatView.ts +11 -4
- package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +12 -3
- package/front_end/panels/ai_assistance/components/chatMessage.css +10 -0
- package/front_end/panels/ai_assistance/components/chatView.css +0 -2
- package/front_end/panels/ai_assistance/components/exportForAgentsDialog.css +13 -0
- package/front_end/panels/application/WebMCPView.ts +126 -30
- package/front_end/panels/application/webMCPView.css +28 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/StylePropertiesSection.ts +0 -4
- package/front_end/panels/elements/elements.ts +3 -0
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +7 -0
- package/front_end/panels/lighthouse/LighthousePanel.ts +7 -1
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +25 -2
- package/front_end/panels/profiler/HeapSnapshotProxy.ts +2 -6
- package/front_end/panels/profiler/HeapSnapshotView.ts +7 -16
- package/front_end/panels/profiler/ProfileHeader.ts +1 -4
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +27 -22
- package/front_end/panels/timeline/TimelinePanel.ts +0 -153
- package/front_end/panels/timeline/TimelineTreeView.ts +11 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/CodeBlock.ts +47 -1
- package/front_end/ui/components/markdown_view/codeBlock.css +8 -0
- package/front_end/ui/legacy/TabbedPane.ts +123 -3
- package/front_end/ui/legacy/Widget.ts +67 -28
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -1
- package/front_end/ui/legacy/components/utils/jsUtils.css +2 -0
- package/front_end/ui/legacy/infobar.css +1 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +0 -1
- package/package.json +1 -1
- package/front_end/core/sdk/WebMCPModel.ts +0 -159
- package/front_end/models/ai_assistance/ConversationHandler.ts +0 -325
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import '../../../ui/components/spinners/spinners.js';
|
|
6
|
+
|
|
5
7
|
import * as Host from '../../../core/host/host.js';
|
|
6
8
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
9
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
|
@@ -80,6 +82,7 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
|
|
|
80
82
|
i18nString(UIStrings.generatingSummary) :
|
|
81
83
|
(isPrompt ? input.state.promptText : input.state.conversationText);
|
|
82
84
|
// clang-format off
|
|
85
|
+
|
|
83
86
|
render(html`
|
|
84
87
|
<style>${styles}</style>
|
|
85
88
|
<div class="export-for-agents-dialog">
|
|
@@ -111,9 +114,15 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
|
|
|
111
114
|
</label>
|
|
112
115
|
</div>
|
|
113
116
|
<main>
|
|
114
|
-
|
|
117
|
+
${input.state.isPromptLoading ? html`
|
|
118
|
+
<span class="prompt-loading">
|
|
119
|
+
<devtools-spinner></devtools-spinner>
|
|
120
|
+
${i18nString(UIStrings.generatingSummary)}
|
|
121
|
+
</span>
|
|
122
|
+
` : Lit.nothing}
|
|
123
|
+
<textarea readonly .value=${input.state.isPromptLoading ? '' : exportText}></textarea>
|
|
115
124
|
</main>
|
|
116
|
-
|
|
125
|
+
<div class="disclaimer">${i18nString(UIStrings.disclaimer)}</div>
|
|
117
126
|
<footer>
|
|
118
127
|
<div class="right-buttons">
|
|
119
128
|
<devtools-button
|
|
@@ -156,7 +165,7 @@ export class ExportForAgentsDialog extends UI.Widget.VBox {
|
|
|
156
165
|
this.#onConversationSaveAs = options.onConversationSaveAs;
|
|
157
166
|
this.#view = view;
|
|
158
167
|
|
|
159
|
-
if (options.promptText
|
|
168
|
+
if (typeof options.promptText !== 'string') {
|
|
160
169
|
void options.promptText.then(promptText => {
|
|
161
170
|
this.#state.promptText = promptText;
|
|
162
171
|
this.#state.isPromptLoading = false;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
justify-content: space-between;
|
|
13
13
|
align-items: center;
|
|
14
14
|
margin-block: calc(-1 * var(--sys-size-3));
|
|
15
|
+
margin-top: var(--sys-size-5);
|
|
15
16
|
|
|
16
17
|
&.not-v2 {
|
|
17
18
|
/* Can be removed when AIv2 ships */
|
|
@@ -126,6 +127,7 @@
|
|
|
126
127
|
.user-query-wrapper {
|
|
127
128
|
display: flex;
|
|
128
129
|
justify-content: flex-end;
|
|
130
|
+
padding: 0 var(--sys-size-5);
|
|
129
131
|
align-items: center;
|
|
130
132
|
}
|
|
131
133
|
|
|
@@ -165,6 +167,10 @@
|
|
|
165
167
|
border-bottom: none;
|
|
166
168
|
}
|
|
167
169
|
|
|
170
|
+
.ai-css-change {
|
|
171
|
+
margin: var(--sys-size-6) 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
168
174
|
&.ai-v2 .answer-body-wrapper {
|
|
169
175
|
@container(min-width: 700px) {
|
|
170
176
|
/* Purposefully not using design system variables, this is a
|
|
@@ -437,6 +443,10 @@
|
|
|
437
443
|
|
|
438
444
|
.widget-name {
|
|
439
445
|
font: var(--sys-typescale-body4-regular);
|
|
446
|
+
max-width: 80%;
|
|
447
|
+
overflow: hidden;
|
|
448
|
+
text-overflow: ellipsis;
|
|
449
|
+
white-space: nowrap; /* stop the titles going onto multiple lines */
|
|
440
450
|
}
|
|
441
451
|
|
|
442
452
|
.widget-reveal-container {
|
|
@@ -63,6 +63,19 @@
|
|
|
63
63
|
border: none;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
main {
|
|
67
|
+
position: relative;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.prompt-loading {
|
|
71
|
+
position: absolute;
|
|
72
|
+
padding: var(--sys-size-5);
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: flex-start;
|
|
76
|
+
gap: var(--sys-size-5);
|
|
77
|
+
}
|
|
78
|
+
|
|
66
79
|
.export-for-agents-dialog .disclaimer {
|
|
67
80
|
margin-top: var(--sys-size-5);
|
|
68
81
|
font: var(--sys-typescale-body4-regular);
|
|
@@ -11,8 +11,10 @@ import * as i18n from '../../core/i18n/i18n.js';
|
|
|
11
11
|
import * as Platform from '../../core/platform/platform.js';
|
|
12
12
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
13
13
|
import * as Protocol from '../../generated/protocol.js';
|
|
14
|
+
import * as WebMCP from '../../models/web_mcp/web_mcp.js';
|
|
14
15
|
import * as Adorners from '../../ui/components/adorners/adorners.js';
|
|
15
16
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
17
|
+
import type * as IconButton from '../../ui/components/icon_button/icon_button.js';
|
|
16
18
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
17
19
|
import {
|
|
18
20
|
Directives,
|
|
@@ -109,6 +111,26 @@ const UIStrings = {
|
|
|
109
111
|
* @description Text for the status of a tool call that has failed
|
|
110
112
|
*/
|
|
111
113
|
pending: 'In Progress',
|
|
114
|
+
/**
|
|
115
|
+
* @description Text for the total number of tool calls
|
|
116
|
+
* @example {2} PH1
|
|
117
|
+
*/
|
|
118
|
+
totalCalls: '{PH1} Total calls',
|
|
119
|
+
/**
|
|
120
|
+
* @description Text for the number of failed tool calls
|
|
121
|
+
* @example {1} PH1
|
|
122
|
+
*/
|
|
123
|
+
failed: '{PH1} Failed',
|
|
124
|
+
/**
|
|
125
|
+
* @description Text for the number of canceled tool calls
|
|
126
|
+
* @example {1} PH1
|
|
127
|
+
*/
|
|
128
|
+
canceledCount: '{PH1} Canceled',
|
|
129
|
+
/**
|
|
130
|
+
* @description Text for the number of in progress tool calls
|
|
131
|
+
* @example {1} PH1
|
|
132
|
+
*/
|
|
133
|
+
inProgressCount: '{PH1} In Progress',
|
|
112
134
|
} as const;
|
|
113
135
|
const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
|
|
114
136
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -136,15 +158,16 @@ export interface FilterMenuButtons {
|
|
|
136
158
|
statusTypes: FilterMenuButton;
|
|
137
159
|
}
|
|
138
160
|
export interface ViewInput {
|
|
139
|
-
tools:
|
|
161
|
+
tools: WebMCP.WebMCPModel.Tool[];
|
|
140
162
|
filters: FilterState;
|
|
141
163
|
filterButtons: FilterMenuButtons;
|
|
142
164
|
onClearLogClick: () => void;
|
|
143
165
|
onFilterChange: (filters: FilterState) => void;
|
|
144
|
-
toolCalls:
|
|
166
|
+
toolCalls: WebMCP.WebMCPModel.Call[];
|
|
145
167
|
}
|
|
146
168
|
|
|
147
|
-
export function filterToolCalls(
|
|
169
|
+
export function filterToolCalls(
|
|
170
|
+
toolCalls: WebMCP.WebMCPModel.Call[], filterState: FilterState): WebMCP.WebMCPModel.Call[] {
|
|
148
171
|
let filtered = [...toolCalls];
|
|
149
172
|
|
|
150
173
|
const statusTypes = filterState.statusTypes;
|
|
@@ -168,11 +191,10 @@ export function filterToolCalls(toolCalls: SDK.WebMCPModel.Call[], filterState:
|
|
|
168
191
|
if (toolTypes) {
|
|
169
192
|
filtered = filtered.filter(call => {
|
|
170
193
|
const {imperative, declarative} = toolTypes;
|
|
171
|
-
|
|
172
|
-
if (imperative && !isDeclarative) {
|
|
194
|
+
if (imperative && !call.tool.isDeclarative) {
|
|
173
195
|
return true;
|
|
174
196
|
}
|
|
175
|
-
if (declarative && isDeclarative) {
|
|
197
|
+
if (declarative && call.tool.isDeclarative) {
|
|
176
198
|
return true;
|
|
177
199
|
}
|
|
178
200
|
return false;
|
|
@@ -190,13 +212,71 @@ export function filterToolCalls(toolCalls: SDK.WebMCPModel.Call[], filterState:
|
|
|
190
212
|
|
|
191
213
|
return filtered;
|
|
192
214
|
}
|
|
193
|
-
|
|
194
215
|
export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
|
216
|
+
function calculateToolStats(calls: WebMCP.WebMCPModel.Call[]):
|
|
217
|
+
{total: number, success: number, failed: number, canceled: number, inProgress: number} {
|
|
218
|
+
let total = 0, success = 0, failed = 0, canceled = 0, inProgress = 0;
|
|
219
|
+
for (const call of calls) {
|
|
220
|
+
total++;
|
|
221
|
+
if (call.result?.status === Protocol.WebMCP.InvocationStatus.Error) {
|
|
222
|
+
failed++;
|
|
223
|
+
} else if (call.result?.status === Protocol.WebMCP.InvocationStatus.Canceled) {
|
|
224
|
+
canceled++;
|
|
225
|
+
} else if (call.result?.status === Protocol.WebMCP.InvocationStatus.Success) {
|
|
226
|
+
success++;
|
|
227
|
+
} else if (call.result === undefined) {
|
|
228
|
+
inProgress++;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return {total, success, failed, canceled, inProgress};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getIconGroupsFromStats(toolStats: ReturnType<typeof calculateToolStats>):
|
|
235
|
+
IconButton.IconButton.IconWithTextData[] {
|
|
236
|
+
const groups = [];
|
|
237
|
+
if (toolStats.success > 0) {
|
|
238
|
+
groups.push({
|
|
239
|
+
iconName: 'check-circle',
|
|
240
|
+
iconColor: 'var(--sys-color-green)',
|
|
241
|
+
iconWidth: '16px',
|
|
242
|
+
iconHeight: '16px',
|
|
243
|
+
text: String(toolStats.success),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
if (toolStats.failed > 0) {
|
|
247
|
+
groups.push({
|
|
248
|
+
iconName: 'cross-circle-filled',
|
|
249
|
+
iconColor: 'var(--sys-color-error)',
|
|
250
|
+
iconWidth: '16px',
|
|
251
|
+
iconHeight: '16px',
|
|
252
|
+
text: String(toolStats.failed),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (toolStats.canceled > 0) {
|
|
256
|
+
groups.push({
|
|
257
|
+
iconName: 'record-stop',
|
|
258
|
+
iconColor: 'var(--sys-color-on-surface-light)',
|
|
259
|
+
iconWidth: '16px',
|
|
260
|
+
iconHeight: '16px',
|
|
261
|
+
text: String(toolStats.canceled),
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (toolStats.inProgress > 0) {
|
|
265
|
+
groups.push({
|
|
266
|
+
iconName: 'dots-circle',
|
|
267
|
+
iconWidth: '16px',
|
|
268
|
+
iconHeight: '16px',
|
|
269
|
+
text: String(toolStats.inProgress),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return groups;
|
|
273
|
+
}
|
|
195
274
|
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
196
275
|
const tools = input.tools;
|
|
276
|
+
const stats = calculateToolStats(input.toolCalls);
|
|
197
277
|
const isFilterActive =
|
|
198
278
|
Boolean(input.filters.text) || Boolean(input.filters.toolTypes) || Boolean(input.filters.statusTypes);
|
|
199
|
-
const iconName = (call:
|
|
279
|
+
const iconName = (call: WebMCP.WebMCPModel.Call): string => {
|
|
200
280
|
switch (call.result?.status) {
|
|
201
281
|
case Protocol.WebMCP.InvocationStatus.Error:
|
|
202
282
|
return 'cross-circle-filled';
|
|
@@ -208,7 +288,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
208
288
|
return '';
|
|
209
289
|
}
|
|
210
290
|
};
|
|
211
|
-
const statusString = (call:
|
|
291
|
+
const statusString = (call: WebMCP.WebMCPModel.Call): string => {
|
|
212
292
|
switch (call.result?.status) {
|
|
213
293
|
case Protocol.WebMCP.InvocationStatus.Error:
|
|
214
294
|
return i18nString(UIStrings.error);
|
|
@@ -282,6 +362,18 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
282
362
|
`)}
|
|
283
363
|
</table>
|
|
284
364
|
</devtools-data-grid>
|
|
365
|
+
<div class="webmcp-toolbar-container" role="toolbar">
|
|
366
|
+
<devtools-toolbar class="webmcp-toolbar" role="presentation" wrappable>
|
|
367
|
+
<span class="toolbar-text">${i18nString(UIStrings.totalCalls, {PH1: stats.total})}</span>
|
|
368
|
+
<div class="toolbar-divider"></div>
|
|
369
|
+
<span class="toolbar-text status-error-text">${i18nString(UIStrings.failed, {PH1: stats.failed})}</span>
|
|
370
|
+
<div class="toolbar-divider"></div>
|
|
371
|
+
<span class="toolbar-text status-cancelled-text">${
|
|
372
|
+
i18nString(UIStrings.canceledCount, {PH1: stats.canceled})}</span>
|
|
373
|
+
<div class="toolbar-divider"></div>
|
|
374
|
+
<span class="toolbar-text">${i18nString(UIStrings.inProgressCount, {PH1: stats.inProgress})}</span>
|
|
375
|
+
</devtools-toolbar>
|
|
376
|
+
</div>
|
|
285
377
|
` : html`
|
|
286
378
|
${UI.Widget.widget(UI.EmptyWidget.EmptyWidget, {header: i18nString(UIStrings.noCallsPlaceholderTitle),
|
|
287
379
|
text: i18nString(UIStrings.noCallsPlaceholder)})}
|
|
@@ -294,14 +386,20 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
294
386
|
text: i18nString(UIStrings.noToolsPlaceholder)})}
|
|
295
387
|
` : html`
|
|
296
388
|
<devtools-list>
|
|
297
|
-
${tools.map(tool =>
|
|
389
|
+
${tools.map(tool => {
|
|
390
|
+
const toolStats = calculateToolStats(input.toolCalls.filter(c => c.tool === tool));
|
|
391
|
+
const groups = getIconGroupsFromStats(toolStats);
|
|
392
|
+
return html`
|
|
298
393
|
<div class="tool-item">
|
|
299
394
|
<div class="tool-name-container">
|
|
300
395
|
<div class="tool-name source-code">${tool.name}</div>
|
|
396
|
+
${groups.length > 0 ? html`<icon-button .data=${
|
|
397
|
+
{groups, compact: false} as IconButton.IconButton.IconButtonData}></icon-button>` : ''}
|
|
301
398
|
</div>
|
|
302
399
|
<div class="tool-description">${tool.description}</div>
|
|
303
400
|
</div>
|
|
304
|
-
|
|
401
|
+
`;
|
|
402
|
+
})}
|
|
305
403
|
</devtools-list>
|
|
306
404
|
`}
|
|
307
405
|
</div>
|
|
@@ -361,9 +459,9 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
361
459
|
this.#showToolTypesContextMenu.bind(this),
|
|
362
460
|
this.#showStatusTypesContextMenu.bind(this),
|
|
363
461
|
);
|
|
364
|
-
SDK.TargetManager.TargetManager.instance().observeModels(
|
|
365
|
-
modelAdded: (model:
|
|
366
|
-
modelRemoved: (model:
|
|
462
|
+
SDK.TargetManager.TargetManager.instance().observeModels(WebMCP.WebMCPModel.WebMCPModel, {
|
|
463
|
+
modelAdded: (model: WebMCP.WebMCPModel.WebMCPModel) => this.#webMCPModelAdded(model),
|
|
464
|
+
modelRemoved: (model: WebMCP.WebMCPModel.WebMCPModel) => this.#webMCPModelRemoved(model),
|
|
367
465
|
});
|
|
368
466
|
this.requestUpdate();
|
|
369
467
|
}
|
|
@@ -408,22 +506,22 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
408
506
|
i18nString(UIStrings.pending), () => toggle('pending'),
|
|
409
507
|
{checked: this.#filterState.statusTypes?.['pending'] ?? false, jslogContext: 'webmcp.pending'});
|
|
410
508
|
}
|
|
411
|
-
#webMCPModelAdded(model:
|
|
412
|
-
model.addEventListener(
|
|
413
|
-
model.addEventListener(
|
|
414
|
-
model.addEventListener(
|
|
415
|
-
model.addEventListener(
|
|
509
|
+
#webMCPModelAdded(model: WebMCP.WebMCPModel.WebMCPModel): void {
|
|
510
|
+
model.addEventListener(WebMCP.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
511
|
+
model.addEventListener(WebMCP.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
|
|
512
|
+
model.addEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this.requestUpdate, this);
|
|
513
|
+
model.addEventListener(WebMCP.WebMCPModel.Events.TOOL_RESPONDED, this.requestUpdate, this);
|
|
416
514
|
}
|
|
417
515
|
|
|
418
|
-
#webMCPModelRemoved(model:
|
|
419
|
-
model.removeEventListener(
|
|
420
|
-
model.removeEventListener(
|
|
421
|
-
model.removeEventListener(
|
|
422
|
-
model.removeEventListener(
|
|
516
|
+
#webMCPModelRemoved(model: WebMCP.WebMCPModel.WebMCPModel): void {
|
|
517
|
+
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
518
|
+
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
|
|
519
|
+
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this.requestUpdate, this);
|
|
520
|
+
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOL_RESPONDED, this.requestUpdate, this);
|
|
423
521
|
}
|
|
424
522
|
|
|
425
523
|
#handleClearLogClick = (): void => {
|
|
426
|
-
const models = SDK.TargetManager.TargetManager.instance().models(
|
|
524
|
+
const models = SDK.TargetManager.TargetManager.instance().models(WebMCP.WebMCPModel.WebMCPModel);
|
|
427
525
|
for (const model of models) {
|
|
428
526
|
model.clearCalls();
|
|
429
527
|
}
|
|
@@ -444,17 +542,15 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
444
542
|
this.requestUpdate();
|
|
445
543
|
};
|
|
446
544
|
|
|
447
|
-
#getTools():
|
|
448
|
-
const models = SDK.TargetManager.TargetManager.instance().models(
|
|
545
|
+
#getTools(): WebMCP.WebMCPModel.Tool[] {
|
|
546
|
+
const models = SDK.TargetManager.TargetManager.instance().models(WebMCP.WebMCPModel.WebMCPModel);
|
|
449
547
|
const tools = models.flatMap(model => model.tools.toArray());
|
|
450
548
|
return tools.sort((a, b) => a.name.localeCompare(b.name));
|
|
451
549
|
}
|
|
452
|
-
|
|
453
550
|
override performUpdate(): void {
|
|
454
|
-
const models = SDK.TargetManager.TargetManager.instance().models(
|
|
551
|
+
const models = SDK.TargetManager.TargetManager.instance().models(WebMCP.WebMCPModel.WebMCPModel);
|
|
455
552
|
const toolCalls = models.flatMap(model => model.toolCalls);
|
|
456
553
|
const filteredCalls = filterToolCalls(toolCalls, this.#filterState);
|
|
457
|
-
|
|
458
554
|
const input: ViewInput = {
|
|
459
555
|
tools: this.#getTools(),
|
|
460
556
|
toolCalls: filteredCalls,
|
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
|
|
50
50
|
devtools-list {
|
|
51
51
|
flex: 1 1 auto;
|
|
52
|
-
margin:
|
|
52
|
+
margin: 0;
|
|
53
|
+
padding: var(--sys-size-4);
|
|
54
|
+
box-sizing: border-box;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
.tool-item {
|
|
@@ -58,17 +60,33 @@
|
|
|
58
60
|
padding: 8px 0;
|
|
59
61
|
gap: 4px;
|
|
60
62
|
width: 100%;
|
|
63
|
+
min-width: 0;
|
|
61
64
|
border-bottom: 1px solid var(--sys-color-divider);
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
.tool-name-container {
|
|
65
68
|
display: flex;
|
|
66
69
|
justify-content: space-between;
|
|
67
|
-
align-items:
|
|
70
|
+
align-items: flex-start;
|
|
71
|
+
gap: 8px;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
.tool-name.source-code {
|
|
71
75
|
color: var(--sys-color-token-string);
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
text-overflow: ellipsis;
|
|
79
|
+
min-width: 0;
|
|
80
|
+
flex: 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* stylelint-disable-next-line selector-type-no-unknown */
|
|
84
|
+
.tool-name-container icon-button {
|
|
85
|
+
flex-shrink: 0;
|
|
86
|
+
height: 0;
|
|
87
|
+
overflow: visible;
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
.tool-description {
|
|
@@ -87,4 +105,12 @@
|
|
|
87
105
|
tr.status-cancelled {
|
|
88
106
|
color: var(--sys-color-on-surface-light);
|
|
89
107
|
}
|
|
108
|
+
|
|
109
|
+
.toolbar-text.status-error-text {
|
|
110
|
+
color: var(--sys-color-error);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.toolbar-text.status-cancelled-text {
|
|
114
|
+
color: var(--sys-color-on-surface-light);
|
|
115
|
+
}
|
|
90
116
|
}
|
|
@@ -878,7 +878,7 @@ function maybeRenderAdAdorner(input: ViewInput): Lit.TemplateResult|typeof nothi
|
|
|
878
878
|
// clang-format off
|
|
879
879
|
return html`
|
|
880
880
|
<devtools-adorner
|
|
881
|
-
aria-
|
|
881
|
+
aria-details=${input.adTooltipId}
|
|
882
882
|
aria-label=${i18nString(UIStrings.thisElementWasIdentifiedAsAnAd)}
|
|
883
883
|
.name=${ElementsComponents.AdornerManager.RegisteredAdorners.AD}
|
|
884
884
|
jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.AD)}
|
|
@@ -1075,10 +1075,6 @@ export class StylePropertiesSection {
|
|
|
1075
1075
|
|
|
1076
1076
|
protected createContainerQueryElement(containerQuery: SDK.CSSContainerQuery.CSSContainerQuery):
|
|
1077
1077
|
ElementsComponents.CSSQuery.CSSQuery|undefined {
|
|
1078
|
-
if (!containerQuery.text) {
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
1078
|
let onQueryTextClick;
|
|
1083
1079
|
if (containerQuery.styleSheetId) {
|
|
1084
1080
|
onQueryTextClick = this.handleQueryRuleClick.bind(this, containerQuery);
|
|
@@ -10,6 +10,7 @@ import './ElementsTreeElement.js';
|
|
|
10
10
|
import './AdoptedStyleSheetTreeElement.js';
|
|
11
11
|
import './TopLayerContainer.js';
|
|
12
12
|
import './ElementsTreeOutline.js';
|
|
13
|
+
import './ImagePreviewPopover.js';
|
|
13
14
|
import './EventListenersWidget.js';
|
|
14
15
|
import './MarkerDecorator.js';
|
|
15
16
|
import './MetricsSidebarPane.js';
|
|
@@ -45,6 +46,7 @@ import * as ElementsTreeElement from './ElementsTreeElement.js';
|
|
|
45
46
|
import * as ElementsTreeOutline from './ElementsTreeOutline.js';
|
|
46
47
|
import * as ElementsTreeOutlineRenderer from './ElementsTreeOutlineRenderer.js';
|
|
47
48
|
import * as EventListenersWidget from './EventListenersWidget.js';
|
|
49
|
+
import * as ImagePreviewPopover from './ImagePreviewPopover.js';
|
|
48
50
|
import * as InspectElementModeController from './InspectElementModeController.js';
|
|
49
51
|
import * as LayersWidget from './LayersWidget.js';
|
|
50
52
|
import * as LayoutPane from './LayoutPane.js';
|
|
@@ -82,6 +84,7 @@ export {
|
|
|
82
84
|
ElementsTreeOutline,
|
|
83
85
|
ElementsTreeOutlineRenderer,
|
|
84
86
|
EventListenersWidget,
|
|
87
|
+
ImagePreviewPopover,
|
|
85
88
|
InspectElementModeController,
|
|
86
89
|
LayersWidget,
|
|
87
90
|
LayoutPane,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
padding-left: 22px;
|
|
22
22
|
white-space: normal;
|
|
23
23
|
text-overflow: ellipsis;
|
|
24
|
+
overflow-wrap: break-word;
|
|
24
25
|
cursor: auto;
|
|
25
26
|
display: block;
|
|
26
27
|
|
|
@@ -74,6 +75,12 @@
|
|
|
74
75
|
overflow-wrap: break-word !important; /* stylelint-disable-line declaration-no-important */
|
|
75
76
|
white-space: normal !important; /* stylelint-disable-line declaration-no-important */
|
|
76
77
|
padding-left: 0;
|
|
78
|
+
|
|
79
|
+
/* Constrain the TextPrompt proxy span (display: inline-block) so that
|
|
80
|
+
long values wrap instead of overflowing the section. */
|
|
81
|
+
> span:has(> .text-prompt-root) {
|
|
82
|
+
max-width: 100%;
|
|
83
|
+
}
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
.info {
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
type PageWarningsChangedEvent
|
|
20
20
|
} from './LighthouseController.js';
|
|
21
21
|
import lighthousePanelStyles from './lighthousePanel.css.js';
|
|
22
|
-
import {ProtocolService} from './LighthouseProtocolService.js';
|
|
22
|
+
import {CancelledError, ProtocolService} from './LighthouseProtocolService.js';
|
|
23
23
|
import {LighthouseReportRenderer} from './LighthouseReportRenderer.js';
|
|
24
24
|
import {Item, ReportSelector} from './LighthouseReportSelector.js';
|
|
25
25
|
import {StartView} from './LighthouseStartView.js';
|
|
@@ -176,6 +176,12 @@ export class LighthousePanel extends UI.Panel.Panel {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
private handleError(err: unknown): void {
|
|
179
|
+
if (err instanceof CancelledError) {
|
|
180
|
+
// If the error was an explicit choice to cancel, we don't want to render
|
|
181
|
+
// the bug report view.
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
179
185
|
if (err instanceof Error) {
|
|
180
186
|
this.statusView.renderBugReport(err);
|
|
181
187
|
}
|
|
@@ -58,6 +58,12 @@ export interface LighthouseRun {
|
|
|
58
58
|
isAIControlled?: boolean;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
export class CancelledError extends Error {
|
|
62
|
+
constructor() {
|
|
63
|
+
super('Lighthouse run cancelled');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
/**
|
|
62
68
|
* ProtocolService manages a connection between the frontend (Lighthouse panel) and the Lighthouse worker.
|
|
63
69
|
*/
|
|
@@ -71,6 +77,14 @@ export class ProtocolService implements ProtocolClient.CDPConnection.CDPConnecti
|
|
|
71
77
|
private configForTesting?: object;
|
|
72
78
|
private connection?: ProtocolClient.CDPConnection.CDPConnection;
|
|
73
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Tracks pending requests to the Lighthouse worker.
|
|
82
|
+
* Key: The message ID sent to the worker.
|
|
83
|
+
* Value: The rejection function for the corresponding promise.
|
|
84
|
+
* This is used to gracefully cancel hanging promises if the ProtocolService is detached before the worker replies.
|
|
85
|
+
*/
|
|
86
|
+
readonly #pendingRequests = new Map<number, (reason: Error) => void>();
|
|
87
|
+
|
|
74
88
|
async attach(): Promise<void> {
|
|
75
89
|
await SDK.TargetManager.TargetManager.instance().suspendAllTargets();
|
|
76
90
|
const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
@@ -174,6 +188,10 @@ export class ProtocolService implements ProtocolClient.CDPConnection.CDPConnecti
|
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
async detach(): Promise<void> {
|
|
191
|
+
for (const reject of this.#pendingRequests.values()) {
|
|
192
|
+
reject(new CancelledError());
|
|
193
|
+
}
|
|
194
|
+
this.#pendingRequests.clear();
|
|
177
195
|
const oldLighthouseWorker = this.lighthouseWorkerPromise;
|
|
178
196
|
const oldRootTarget = this.rootTarget;
|
|
179
197
|
|
|
@@ -245,7 +263,7 @@ export class ProtocolService implements ProtocolClient.CDPConnection.CDPConnecti
|
|
|
245
263
|
return this.lighthouseWorkerPromise;
|
|
246
264
|
}
|
|
247
265
|
|
|
248
|
-
|
|
266
|
+
async ensureWorkerExists(): Promise<Worker> {
|
|
249
267
|
let worker: Worker;
|
|
250
268
|
if (!this.lighthouseWorkerPromise) {
|
|
251
269
|
worker = await this.initWorker();
|
|
@@ -293,16 +311,21 @@ export class ProtocolService implements ProtocolClient.CDPConnection.CDPConnecti
|
|
|
293
311
|
Promise<LighthouseModel.ReporterTypes.RunnerResult> {
|
|
294
312
|
const worker = await this.ensureWorkerExists();
|
|
295
313
|
const messageId = lastId++;
|
|
296
|
-
const messageResult = new Promise<LighthouseModel.ReporterTypes.RunnerResult>(resolve => {
|
|
314
|
+
const messageResult = new Promise<LighthouseModel.ReporterTypes.RunnerResult>((resolve, reject) => {
|
|
297
315
|
const workerListener = (event: MessageEvent): void => {
|
|
298
316
|
const lighthouseMessage = event.data;
|
|
299
317
|
|
|
300
318
|
if (lighthouseMessage.id === messageId) {
|
|
301
319
|
worker.removeEventListener('message', workerListener);
|
|
320
|
+
this.#pendingRequests.delete(messageId);
|
|
302
321
|
resolve(lighthouseMessage.result);
|
|
303
322
|
}
|
|
304
323
|
};
|
|
305
324
|
worker.addEventListener('message', workerListener);
|
|
325
|
+
this.#pendingRequests.set(messageId, (err: Error) => {
|
|
326
|
+
worker.removeEventListener('message', workerListener);
|
|
327
|
+
reject(err);
|
|
328
|
+
});
|
|
306
329
|
});
|
|
307
330
|
worker.postMessage({id: messageId, action, args: {...args, id: messageId}});
|
|
308
331
|
|
|
@@ -23,9 +23,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
23
23
|
readonly eventHandler: (arg0: string, arg1: string) => void;
|
|
24
24
|
nextObjectId = 1;
|
|
25
25
|
nextCallId = 1;
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
-
callbacks = new Map<number, (arg0: any) => void>();
|
|
26
|
+
callbacks = new Map<number, (...args: any[]) => void>();
|
|
29
27
|
readonly previousCallbacks = new Set<number>();
|
|
30
28
|
readonly worker: PlatformApi.HostRuntime.Worker;
|
|
31
29
|
interval?: number;
|
|
@@ -53,9 +51,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
53
51
|
|
|
54
52
|
dispose(): void {
|
|
55
53
|
this.worker.terminate();
|
|
56
|
-
|
|
57
|
-
clearInterval(this.interval);
|
|
58
|
-
}
|
|
54
|
+
clearInterval(this.interval);
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
disposeObject(objectId: number): void {
|