chrome-devtools-frontend 1.0.1625854 → 1.0.1626840
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/AidaClient.ts +1 -1
- package/front_end/core/host/AidaClientTypes.ts +2 -0
- package/front_end/core/host/AidaGcaTranslation.ts +2 -2
- package/front_end/core/host/UserMetrics.ts +11 -6
- package/front_end/core/root/ExperimentNames.ts +1 -1
- package/front_end/core/sdk/CSSMetadata.ts +60 -55
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +11 -2
- package/front_end/core/sdk/HeapProfilerModel.ts +1 -11
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -1
- package/front_end/entrypoints/main/MainImpl.ts +4 -29
- package/front_end/generated/InspectorBackendCommands.ts +3 -2
- package/front_end/generated/protocol-mapping.d.ts +5 -0
- package/front_end/generated/protocol-proxy-api.d.ts +4 -0
- package/front_end/generated/protocol.ts +21 -0
- package/front_end/models/ai_assistance/StorageItem.ts +16 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +11 -5
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +82 -0
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +9 -37
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +26 -3
- package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
- package/front_end/models/lighthouse/RunTypes.ts +1 -1
- package/front_end/models/web_mcp/WebMCPModel.ts +11 -2
- package/front_end/models/workspace/UISourceCode.ts +0 -1
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +6 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -3
- package/front_end/panels/application/WebMCPView.ts +74 -16
- package/front_end/panels/application/webMCPView.css +13 -2
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +9 -0
- package/front_end/panels/elements/StandaloneStylesContainer.ts +3 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +35 -2
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +1 -1
- package/front_end/panels/elements/StylesContainer.ts +1 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +10 -4
- package/front_end/panels/emulation/DeviceModeToolbar.ts +7 -3
- package/front_end/panels/lighthouse/LighthouseController.ts +18 -0
- package/front_end/panels/profiler/profiler-meta.ts +0 -71
- package/front_end/panels/profiler/profiler.ts +0 -2
- package/front_end/panels/sources/ProfilePlugin.ts +12 -65
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +5 -1
- package/front_end/panels/sources/UISourceCodeFrame.ts +1 -2
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +179 -145
- package/front_end/panels/timeline/timelineTreeView.css +2 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +4213 -4208
- package/front_end/third_party/lighthouse/locales/en-US.json +26 -8
- package/front_end/third_party/lighthouse/locales/en-XL.json +26 -8
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +7 -1
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +8 -1
- package/front_end/ui/components/tooltips/Tooltip.ts +3 -3
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -56
- package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -35
- package/front_end/ui/legacy/components/perf_ui/perf_ui.ts +0 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/package.json +1 -1
- package/front_end/panels/profiler/LiveHeapProfileView.ts +0 -405
- package/front_end/panels/profiler/liveHeapProfile.css +0 -22
- package/front_end/ui/legacy/components/perf_ui/LiveHeapProfile.ts +0 -113
|
@@ -14,6 +14,7 @@ import * as NetworkAgent from './agents/NetworkAgent.js';
|
|
|
14
14
|
import * as PatchAgent from './agents/PatchAgent.js';
|
|
15
15
|
import * as PerformanceAgent from './agents/PerformanceAgent.js';
|
|
16
16
|
import * as PerformanceAnnotationsAgent from './agents/PerformanceAnnotationsAgent.js';
|
|
17
|
+
import * as StorageAgent from './agents/StorageAgent.js';
|
|
17
18
|
import * as StylingAgent from './agents/StylingAgent.js';
|
|
18
19
|
import * as AiConversation from './AiConversation.js';
|
|
19
20
|
import * as AiHistoryStorage from './AiHistoryStorage.js';
|
|
@@ -33,6 +34,7 @@ import * as Injected from './injected.js';
|
|
|
33
34
|
import * as AICallTree from './performance/AICallTree.js';
|
|
34
35
|
import * as AIContext from './performance/AIContext.js';
|
|
35
36
|
import * as AIQueries from './performance/AIQueries.js';
|
|
37
|
+
import * as StorageItem from './StorageItem.js';
|
|
36
38
|
|
|
37
39
|
export {
|
|
38
40
|
AccessibilityAgent,
|
|
@@ -64,6 +66,8 @@ export {
|
|
|
64
66
|
PerformanceAnnotationsAgent,
|
|
65
67
|
PerformanceInsightFormatter,
|
|
66
68
|
PerformanceTraceFormatter,
|
|
69
|
+
StorageAgent,
|
|
70
|
+
StorageItem,
|
|
67
71
|
StylingAgent,
|
|
68
72
|
UnitFormatters,
|
|
69
73
|
};
|
package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt
CHANGED
|
@@ -332,33 +332,21 @@ IMPORTANT: Never show eventKey to the user.
|
|
|
332
332
|
|
|
333
333
|
The following are markdown block(s) of code that ran in the page, each representing a separate function. <FUNCTION_START> and <FUNCTION_END> marks the exact function declaration, and everything outside that is provided for additional context. Comments at the end of each line indicate the runtime performance cost of that code. Do not show the user the function markers or the additional context.
|
|
334
334
|
|
|
335
|
-
Here
|
|
335
|
+
Here is the first line of 3 relevant functions:
|
|
336
336
|
|
|
337
|
-
(anonymous) @ https://s.yimg.com/aaq/prebid/prebid-2.0.js:12:53984
|
|
337
|
+
(anonymous) @ https://s.yimg.com/aaq/prebid/prebid-2.0.js:12:53984
|
|
338
338
|
```
|
|
339
|
-
// context ...
|
|
340
|
-
|
|
341
339
|
() => { /* some code from https://s.yimg.com/aaq/prebid/prebid-2.0.js... */ }
|
|
342
|
-
|
|
343
|
-
// context ...
|
|
344
340
|
```
|
|
345
341
|
|
|
346
|
-
(anonymous) @ https://s.yimg.com/aaq/f10d509c/d1irmdsmbztlvx.js:0:43042
|
|
342
|
+
(anonymous) @ https://s.yimg.com/aaq/f10d509c/d1irmdsmbztlvx.js:0:43042
|
|
347
343
|
```
|
|
348
|
-
// context ...
|
|
349
|
-
|
|
350
344
|
() => { /* some code from https://s.yimg.com/aaq/f10d509c/d1irmdsmbztlvx.js... */ }
|
|
351
|
-
|
|
352
|
-
// context ...
|
|
353
345
|
```
|
|
354
346
|
|
|
355
|
-
(anonymous) @ https://s.yimg.com/aaq/prebid/prebid-2.0.js:12:15854
|
|
347
|
+
(anonymous) @ https://s.yimg.com/aaq/prebid/prebid-2.0.js:12:15854
|
|
356
348
|
```
|
|
357
|
-
// context ...
|
|
358
|
-
|
|
359
349
|
() => { /* some code from https://s.yimg.com/aaq/prebid/prebid-2.0.js... */ }
|
|
360
|
-
|
|
361
|
-
// context ...
|
|
362
350
|
```
|
|
363
351
|
|
|
364
352
|
# Bottom-up main thread summary
|
|
@@ -1019,42 +1007,26 @@ IMPORTANT: Never show eventKey to the user.
|
|
|
1019
1007
|
|
|
1020
1008
|
The following are markdown block(s) of code that ran in the page, each representing a separate function. <FUNCTION_START> and <FUNCTION_END> marks the exact function declaration, and everything outside that is provided for additional context. Comments at the end of each line indicate the runtime performance cost of that code. Do not show the user the function markers or the additional context.
|
|
1021
1009
|
|
|
1022
|
-
Here
|
|
1010
|
+
Here is the first line of 4 relevant functions:
|
|
1023
1011
|
|
|
1024
|
-
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:0
|
|
1012
|
+
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:0
|
|
1025
1013
|
```
|
|
1026
|
-
// context ...
|
|
1027
|
-
|
|
1028
1014
|
() => { /* some code from https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js... */ }
|
|
1029
|
-
|
|
1030
|
-
// context ...
|
|
1031
1015
|
```
|
|
1032
1016
|
|
|
1033
|
-
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:231
|
|
1017
|
+
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:231
|
|
1034
1018
|
```
|
|
1035
|
-
// context ...
|
|
1036
|
-
|
|
1037
1019
|
() => { /* some code from https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js... */ }
|
|
1038
|
-
|
|
1039
|
-
// context ...
|
|
1040
1020
|
```
|
|
1041
1021
|
|
|
1042
|
-
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:292
|
|
1022
|
+
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:292
|
|
1043
1023
|
```
|
|
1044
|
-
// context ...
|
|
1045
|
-
|
|
1046
1024
|
() => { /* some code from https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js... */ }
|
|
1047
|
-
|
|
1048
|
-
// context ...
|
|
1049
1025
|
```
|
|
1050
1026
|
|
|
1051
|
-
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:155034
|
|
1027
|
+
(anonymous) @ https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js:0:155034
|
|
1052
1028
|
```
|
|
1053
|
-
// context ...
|
|
1054
|
-
|
|
1055
1029
|
() => { /* some code from https://www.gstatic.com/firebasejs/6.6.1/firebase-auth.js... */ }
|
|
1056
|
-
|
|
1057
|
-
// context ...
|
|
1058
1030
|
```
|
|
1059
1031
|
=== end content
|
|
1060
1032
|
|
|
@@ -901,6 +901,29 @@ The order of headers corresponds to an internal fixed list. If a header is not p
|
|
|
901
901
|
return parts.join('\n');
|
|
902
902
|
}
|
|
903
903
|
|
|
904
|
+
/**
|
|
905
|
+
* Formats only the first line of the function code to save space in summaries.
|
|
906
|
+
* The agent can use this information (url, line, column) to get the whole function source.
|
|
907
|
+
*/
|
|
908
|
+
#formatFunctionCodeSummary(code: SourceMapScopes.FunctionCodeResolver.FunctionCode): string {
|
|
909
|
+
this.#formattedFunctionCodes.add(this.#functionCodeToKey(code));
|
|
910
|
+
|
|
911
|
+
const {startLine, startColumn} = code.range;
|
|
912
|
+
const name = code.functionBounds.name || '(anonymous)';
|
|
913
|
+
const url = code.functionBounds.uiSourceCode.url();
|
|
914
|
+
|
|
915
|
+
const lines = code.code.split('\n');
|
|
916
|
+
const firstLine = lines[0] || '';
|
|
917
|
+
|
|
918
|
+
const parts = [];
|
|
919
|
+
parts.push(`${name} @ ${url}:${startLine}:${startColumn}`);
|
|
920
|
+
parts.push('```');
|
|
921
|
+
parts.push(firstLine);
|
|
922
|
+
parts.push('```');
|
|
923
|
+
|
|
924
|
+
return parts.join('\n');
|
|
925
|
+
}
|
|
926
|
+
|
|
904
927
|
/**
|
|
905
928
|
* Appends the code of each call frame's function, but only if the function was not
|
|
906
929
|
* serialized previously.
|
|
@@ -917,7 +940,7 @@ The order of headers corresponds to an internal fixed list. If a header is not p
|
|
|
917
940
|
resolveFunctionCode(frame.url as Platform.DevToolsPath.UrlString, frame.lineNumber, frame.columnNumber)));
|
|
918
941
|
for (const code of functionCodes) {
|
|
919
942
|
if (code && !this.#hasFormattedFunctionCode(code)) {
|
|
920
|
-
functionCodeStrings.push(this.#
|
|
943
|
+
functionCodeStrings.push(this.#formatFunctionCodeSummary(code));
|
|
921
944
|
}
|
|
922
945
|
}
|
|
923
946
|
|
|
@@ -927,8 +950,8 @@ The order of headers corresponds to an internal fixed list. If a header is not p
|
|
|
927
950
|
|
|
928
951
|
return '\n' + [
|
|
929
952
|
this.#getFormattedFunctionCodeExplainer(),
|
|
930
|
-
functionCodeStrings.length > 1 ? `Here
|
|
931
|
-
`Here is a relevant function:`,
|
|
953
|
+
functionCodeStrings.length > 1 ? `Here is the first line of ${functionCodeStrings.length} relevant functions:` :
|
|
954
|
+
`Here is the first line of a relevant function:`,
|
|
932
955
|
...functionCodeStrings,
|
|
933
956
|
].join('\n\n');
|
|
934
957
|
}
|
|
@@ -7960,10 +7960,6 @@ export const NativeFunctions = [
|
|
|
7960
7960
|
name: "strokeTextCluster",
|
|
7961
7961
|
signatures: [["textCluster","x","y","?options"]]
|
|
7962
7962
|
},
|
|
7963
|
-
{
|
|
7964
|
-
name: "transferToGPUTexture",
|
|
7965
|
-
signatures: [["options"]]
|
|
7966
|
-
},
|
|
7967
7963
|
{
|
|
7968
7964
|
name: "beginLayer",
|
|
7969
7965
|
signatures: [["?options"]]
|
|
@@ -5,7 +5,7 @@ import type * as Common from '../../core/common/common.js';
|
|
|
5
5
|
import type * as Host from '../../core/host/host.js';
|
|
6
6
|
import type * as Platform from '../../core/platform/platform.js';
|
|
7
7
|
|
|
8
|
-
export type CategoryId = 'performance'|'accessibility'|'best-practices'|'seo';
|
|
8
|
+
export type CategoryId = 'performance'|'accessibility'|'best-practices'|'seo'|'agentic-browsing';
|
|
9
9
|
export type RunMode = 'navigation'|'timespan'|'snapshot';
|
|
10
10
|
|
|
11
11
|
export interface Preset {
|
|
@@ -147,12 +147,17 @@ export class Tool {
|
|
|
147
147
|
new SDK.DOMModel.DeferredDOMNode(target, this.#protocolTool.backendNodeId);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
async invoke(input: unknown): Promise<
|
|
151
|
-
|
|
150
|
+
async invoke(input: unknown): Promise<string|undefined> {
|
|
151
|
+
const target = this.#target.deref();
|
|
152
|
+
const response = await target?.webMCPAgent().invoke_invokeTool({
|
|
152
153
|
toolName: this.name,
|
|
153
154
|
frameId: this.#protocolTool.frameId,
|
|
154
155
|
input,
|
|
155
156
|
});
|
|
157
|
+
if (!response || response.getError()) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return response.invocationId;
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
export interface EventTypes {
|
|
@@ -190,6 +195,10 @@ export class WebMCPModel extends SDK.SDKModel.SDKModel<EventTypes> implements Pr
|
|
|
190
195
|
return [...this.#calls.values()];
|
|
191
196
|
}
|
|
192
197
|
|
|
198
|
+
toolCallForId(invocationId: string): Call|undefined {
|
|
199
|
+
return this.#calls.get(invocationId);
|
|
200
|
+
}
|
|
201
|
+
|
|
193
202
|
clearCalls(): void {
|
|
194
203
|
this.#calls.clear();
|
|
195
204
|
}
|
|
@@ -115,9 +115,14 @@ function isFileAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean
|
|
|
115
115
|
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceFileAgent?.enabled)) === true;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
function isStorageAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
|
|
119
|
+
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceStorageAgent?.enabled)) === true;
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
function isAnyFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
|
|
119
123
|
return isStylingAgentFeatureAvailable(config) || isNetworkAgentFeatureAvailable(config) ||
|
|
120
|
-
isPerformanceAgentFeatureAvailable(config) || isFileAgentFeatureAvailable(config)
|
|
124
|
+
isPerformanceAgentFeatureAvailable(config) || isFileAgentFeatureAvailable(config) ||
|
|
125
|
+
isStorageAgentFeatureAvailable(config);
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
UI.ViewManager.registerViewExtension({
|
|
@@ -1330,17 +1330,18 @@ function renderNetworkRequestPreview(networkRequest: NonNullable<DomTreeAiWidget
|
|
|
1330
1330
|
const resourceType = Common.ResourceType.resourceTypes[networkRequest.resourceType];
|
|
1331
1331
|
const {iconName, color} = PanelUtils.iconDataForResourceType(resourceType);
|
|
1332
1332
|
|
|
1333
|
+
const imageUrl = networkRequest.imageContent?.asImagePreviewUrl() ?? networkRequest.url;
|
|
1334
|
+
|
|
1333
1335
|
return html`
|
|
1334
1336
|
<div class="network-request-preview">
|
|
1335
1337
|
<div class="network-request-header">
|
|
1336
1338
|
<div class="network-request-icon">
|
|
1337
1339
|
${
|
|
1338
|
-
resourceType.isImage() ? html`<img src=${
|
|
1340
|
+
resourceType.isImage() ? html`<img src=${imageUrl} alt=${filename} />` :
|
|
1339
1341
|
html`<devtools-icon name=${iconName} style=${Lit.Directives.styleMap({
|
|
1340
1342
|
color: color ?? ''
|
|
1341
1343
|
})}></devtools-icon>`}
|
|
1342
|
-
</div>
|
|
1343
|
-
<div class="network-request-details">
|
|
1344
|
+
</div> <div class="network-request-details">
|
|
1344
1345
|
<div class="network-request-name" title=${networkRequest.url}>${filename}</div>
|
|
1345
1346
|
<div class="network-request-size">${size}</div>
|
|
1346
1347
|
</div>
|
|
@@ -191,6 +191,10 @@ const UIStrings = {
|
|
|
191
191
|
* @description Notice to display when a tool has been unregistered
|
|
192
192
|
*/
|
|
193
193
|
toolUnregisteredNotice: 'This tool has been unregistered',
|
|
194
|
+
/**
|
|
195
|
+
* @description Text preceding a nested error in a stack trace
|
|
196
|
+
*/
|
|
197
|
+
causedBy: 'Caused by:',
|
|
194
198
|
} as const;
|
|
195
199
|
const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
|
|
196
200
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -219,6 +223,11 @@ export interface FilterMenuButtons {
|
|
|
219
223
|
toolTypes: FilterMenuButton;
|
|
220
224
|
statusTypes: FilterMenuButton;
|
|
221
225
|
}
|
|
226
|
+
export const enum TabId {
|
|
227
|
+
DETAILS = 'webmcp.tool-details',
|
|
228
|
+
INPUT = 'webmcp.call-inputs',
|
|
229
|
+
OUTPUT = 'webmcp.call-outputs',
|
|
230
|
+
}
|
|
222
231
|
export interface SelectedTool {
|
|
223
232
|
tool: WebMCP.WebMCPModel.Tool;
|
|
224
233
|
parameters?: Record<string, unknown>;
|
|
@@ -229,7 +238,8 @@ export interface ViewInput {
|
|
|
229
238
|
onToolSelect: (tool: WebMCP.WebMCPModel.Tool|null) => void;
|
|
230
239
|
onRevealTool: (tool: WebMCP.WebMCPModel.Tool, parameters?: Record<string, unknown>) => void;
|
|
231
240
|
selectedCall: WebMCP.WebMCPModel.Call|null;
|
|
232
|
-
|
|
241
|
+
selectedTab?: TabId;
|
|
242
|
+
onCallSelect: (call: WebMCP.WebMCPModel.Call|null, tabId?: TabId) => void;
|
|
233
243
|
filters: FilterState;
|
|
234
244
|
filterButtons: FilterMenuButtons;
|
|
235
245
|
onClearLogClick: () => void;
|
|
@@ -508,7 +518,10 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
508
518
|
}, {jslogContext: 'webmcp.cancel-call'});
|
|
509
519
|
}
|
|
510
520
|
}}>
|
|
511
|
-
<td
|
|
521
|
+
<td @click=${(e: Event) => {
|
|
522
|
+
e.stopPropagation();
|
|
523
|
+
input.onCallSelect(call, TabId.DETAILS);
|
|
524
|
+
}}>
|
|
512
525
|
<div class="name-cell">
|
|
513
526
|
<span>${call.tool.name}</span>
|
|
514
527
|
<button class="run-tool-action-button"
|
|
@@ -524,7 +537,10 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
524
537
|
</button>
|
|
525
538
|
</div>
|
|
526
539
|
</td>
|
|
527
|
-
<td
|
|
540
|
+
<td @click=${(e: Event) => {
|
|
541
|
+
e.stopPropagation();
|
|
542
|
+
input.onCallSelect(call, TabId.OUTPUT);
|
|
543
|
+
}}>
|
|
528
544
|
<div class="status-cell">
|
|
529
545
|
${iconName(call) ? html`<devtools-icon class="small" name=${iconName(call)}></devtools-icon>`
|
|
530
546
|
: ''}
|
|
@@ -532,8 +548,14 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
532
548
|
</div>
|
|
533
549
|
</td>
|
|
534
550
|
${!input.selectedCall ? html`
|
|
535
|
-
<td
|
|
536
|
-
|
|
551
|
+
<td @click=${(e: Event) => {
|
|
552
|
+
e.stopPropagation();
|
|
553
|
+
input.onCallSelect(call, TabId.INPUT);
|
|
554
|
+
}}>${call.input}</td>
|
|
555
|
+
<td @click=${(e: Event) => {
|
|
556
|
+
e.stopPropagation();
|
|
557
|
+
input.onCallSelect(call, TabId.OUTPUT);
|
|
558
|
+
}}>${call.result?.output ? JSON.stringify(call.result.output)
|
|
537
559
|
: call.result?.errorText ?? ''}</td>
|
|
538
560
|
` : nothing}
|
|
539
561
|
</tr>
|
|
@@ -552,17 +574,20 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
552
574
|
@click=${() => input.onCallSelect(null)}
|
|
553
575
|
></devtools-button>
|
|
554
576
|
<devtools-widget
|
|
555
|
-
id
|
|
577
|
+
id=${TabId.DETAILS}
|
|
578
|
+
?selected=${input.selectedTab === TabId.DETAILS}
|
|
556
579
|
title=${i18nString(UIStrings.toolDetails)}
|
|
557
580
|
${widget(ToolDetailsWidget, {tool: input.selectedCall?.tool, isUnregistered: input.selectedCall ? !input.tools.includes(input.selectedCall.tool) : false})}>
|
|
558
581
|
</devtools-widget>
|
|
559
582
|
<devtools-widget
|
|
560
|
-
id
|
|
583
|
+
id=${TabId.INPUT}
|
|
584
|
+
?selected=${input.selectedTab === TabId.INPUT}
|
|
561
585
|
title=${i18nString(UIStrings.input)}
|
|
562
586
|
${widget(PayloadWidget, parsePayload(input.selectedCall?.input))}>
|
|
563
587
|
</devtools-widget>
|
|
564
588
|
<devtools-widget
|
|
565
|
-
id
|
|
589
|
+
id=${TabId.OUTPUT}
|
|
590
|
+
?selected=${input.selectedTab === TabId.OUTPUT}
|
|
566
591
|
title=${i18nString(UIStrings.output)}
|
|
567
592
|
${widget(PayloadWidget, {
|
|
568
593
|
valueObject: input.selectedCall?.result?.output,
|
|
@@ -697,6 +722,8 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
697
722
|
readonly #view: View;
|
|
698
723
|
#selectedTool: SelectedTool|null = null;
|
|
699
724
|
#selectedCall: WebMCP.WebMCPModel.Call|null = null;
|
|
725
|
+
#selectedTab: TabId|undefined = undefined;
|
|
726
|
+
#lastDevToolsInvocationId: string|null = null;
|
|
700
727
|
|
|
701
728
|
#filterState: FilterState = {
|
|
702
729
|
text: '',
|
|
@@ -799,17 +826,26 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
799
826
|
#webMCPModelAdded(model: WebMCP.WebMCPModel.WebMCPModel): void {
|
|
800
827
|
model.addEventListener(WebMCP.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
801
828
|
model.addEventListener(WebMCP.WebMCPModel.Events.TOOLS_REMOVED, this.#toolsRemoved, this);
|
|
802
|
-
model.addEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this
|
|
829
|
+
model.addEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this.#toolInvoked, this);
|
|
803
830
|
model.addEventListener(WebMCP.WebMCPModel.Events.TOOL_RESPONDED, this.requestUpdate, this);
|
|
804
831
|
}
|
|
805
832
|
|
|
806
833
|
#webMCPModelRemoved(model: WebMCP.WebMCPModel.WebMCPModel): void {
|
|
807
834
|
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
808
835
|
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOLS_REMOVED, this.#toolsRemoved, this);
|
|
809
|
-
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this
|
|
836
|
+
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOL_INVOKED, this.#toolInvoked, this);
|
|
810
837
|
model.removeEventListener(WebMCP.WebMCPModel.Events.TOOL_RESPONDED, this.requestUpdate, this);
|
|
811
838
|
}
|
|
812
839
|
|
|
840
|
+
#toolInvoked(event: Common.EventTarget.EventTargetEvent<WebMCP.WebMCPModel.Call>): void {
|
|
841
|
+
const call = event.data;
|
|
842
|
+
if (call.invocationId === this.#lastDevToolsInvocationId) {
|
|
843
|
+
this.#selectedCall = call;
|
|
844
|
+
this.#lastDevToolsInvocationId = null;
|
|
845
|
+
}
|
|
846
|
+
this.requestUpdate();
|
|
847
|
+
}
|
|
848
|
+
|
|
813
849
|
#toolsRemoved(event: Common.EventTarget.EventTargetEvent<readonly WebMCP.WebMCPModel.Tool[]>): void {
|
|
814
850
|
if (this.#selectedTool && event.data.includes(this.#selectedTool.tool)) {
|
|
815
851
|
this.#selectedTool = null;
|
|
@@ -861,8 +897,16 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
861
897
|
this.requestUpdate();
|
|
862
898
|
},
|
|
863
899
|
selectedCall: this.#selectedCall,
|
|
864
|
-
|
|
865
|
-
|
|
900
|
+
selectedTab: this.#selectedTab,
|
|
901
|
+
onCallSelect: (call, tabId) => {
|
|
902
|
+
if (call === null) {
|
|
903
|
+
this.#selectedCall = null;
|
|
904
|
+
} else if (this.#selectedCall === null) {
|
|
905
|
+
this.#selectedCall = call;
|
|
906
|
+
this.#selectedTab = tabId;
|
|
907
|
+
} else {
|
|
908
|
+
this.#selectedCall = call;
|
|
909
|
+
}
|
|
866
910
|
this.requestUpdate();
|
|
867
911
|
},
|
|
868
912
|
toolCalls: filteredCalls,
|
|
@@ -870,9 +914,20 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
870
914
|
filterButtons: this.#filterButtons,
|
|
871
915
|
onClearLogClick: this.#handleClearLogClick,
|
|
872
916
|
onFilterChange: this.#handleFilterChange,
|
|
873
|
-
onRunTool: event => {
|
|
917
|
+
onRunTool: async event => {
|
|
874
918
|
if (this.#selectedTool) {
|
|
875
|
-
|
|
919
|
+
this.#selectedTool.parameters = event.data.parameters || {};
|
|
920
|
+
this.#lastDevToolsInvocationId = await this.#selectedTool.tool.invoke(this.#selectedTool.parameters) ?? null;
|
|
921
|
+
if (this.#lastDevToolsInvocationId) {
|
|
922
|
+
const models = SDK.TargetManager.TargetManager.instance().models(WebMCP.WebMCPModel.WebMCPModel);
|
|
923
|
+
const call =
|
|
924
|
+
models.flatMap(model => model.toolCalls).find(c => c.invocationId === this.#lastDevToolsInvocationId);
|
|
925
|
+
if (call) {
|
|
926
|
+
this.#selectedCall = call;
|
|
927
|
+
this.#lastDevToolsInvocationId = null;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
this.requestUpdate();
|
|
876
931
|
}
|
|
877
932
|
},
|
|
878
933
|
onPaste: async () => {
|
|
@@ -891,6 +946,7 @@ export class WebMCPView extends UI.Widget.VBox {
|
|
|
891
946
|
},
|
|
892
947
|
};
|
|
893
948
|
this.#view(input, {}, this.contentElement);
|
|
949
|
+
this.#selectedTab = undefined;
|
|
894
950
|
}
|
|
895
951
|
}
|
|
896
952
|
export interface PayloadViewInput {
|
|
@@ -972,7 +1028,9 @@ export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, ta
|
|
|
972
1028
|
<div class="payload-value source-code error-text">
|
|
973
1029
|
${details.frames.length === 0 && details.description ? html`<span>${details.description}\n</span>` : nothing}
|
|
974
1030
|
<div>${details.frames.map(renderFrame)}</div>
|
|
975
|
-
${
|
|
1031
|
+
${
|
|
1032
|
+
details.cause ? html`\n${i18nString(UIStrings.causedBy)}\n${createException(details.cause, linkifier)}` :
|
|
1033
|
+
nothing}</div>`;
|
|
976
1034
|
};
|
|
977
1035
|
|
|
978
1036
|
render(
|
|
@@ -1124,7 +1182,7 @@ const TOOL_DETAILS_VIEW = (input: ToolDetailsViewInput, output: undefined, targe
|
|
|
1124
1182
|
></devtools-button>
|
|
1125
1183
|
</div>` : origin ? html`
|
|
1126
1184
|
<div class="label">Origin</div>
|
|
1127
|
-
<div class="value">
|
|
1185
|
+
<div class="value stack-trace">
|
|
1128
1186
|
${widget(Components.JSPresentationUtils.StackTracePreviewContent,
|
|
1129
1187
|
{stackTrace: origin, options: { expandable: true}})}
|
|
1130
1188
|
</div>` : nothing}
|
|
@@ -88,6 +88,14 @@
|
|
|
88
88
|
display: flex;
|
|
89
89
|
gap: var(--sys-size-5);
|
|
90
90
|
align-items: center;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.name-cell > span {
|
|
95
|
+
white-space: nowrap;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
text-overflow: ellipsis;
|
|
98
|
+
min-width: 0;
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
.run-tool-action-button {
|
|
@@ -141,8 +149,11 @@
|
|
|
141
149
|
color: var(--sys-color-on-surface);
|
|
142
150
|
overflow-wrap: anywhere;
|
|
143
151
|
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
&.stack-trace {
|
|
153
|
+
display: flex;
|
|
154
|
+
padding: 0;
|
|
155
|
+
margin-top: calc(-1 * (var(--sys-size-1) + var(--sys-size-2)));
|
|
156
|
+
margin-left: calc(-1 * var(--sys-size-3));
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
&.tool-origin-container {
|
|
@@ -9,6 +9,7 @@ import * as Host from '../../core/host/host.js';
|
|
|
9
9
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
10
10
|
import * as Root from '../../core/root/root.js';
|
|
11
11
|
import * as AIAssistance from '../../models/ai_assistance/ai_assistance.js';
|
|
12
|
+
import * as AiCodeCompletion from '../../models/ai_code_completion/ai_code_completion.js';
|
|
12
13
|
import * as AiCodeGeneration from '../../models/ai_code_generation/ai_code_generation.js';
|
|
13
14
|
import * as Snackbars from '../../ui/components/snackbars/snackbars.js';
|
|
14
15
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
@@ -163,6 +164,7 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
163
164
|
|
|
164
165
|
interface AiCodeCompletionTeaserConfig {
|
|
165
166
|
onDetach: () => void;
|
|
167
|
+
panel?: AiCodeCompletion.AiCodeCompletion.ContextFlavor;
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
@@ -172,6 +174,7 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
|
172
174
|
#boundOnAidaAvailabilityChange: () => Promise<void>;
|
|
173
175
|
#boundOnAiCodeCompletionSettingChanged: () => void;
|
|
174
176
|
#onDetach: () => void;
|
|
177
|
+
#panel?: AiCodeCompletion.AiCodeCompletion.ContextFlavor;
|
|
175
178
|
|
|
176
179
|
// Whether the user completed first run experience dialog or not.
|
|
177
180
|
#aiCodeCompletionFreCompletedSetting =
|
|
@@ -186,6 +189,7 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
|
186
189
|
super();
|
|
187
190
|
this.markAsExternallyManaged();
|
|
188
191
|
this.#onDetach = config.onDetach;
|
|
192
|
+
this.#panel = config.panel;
|
|
189
193
|
this.#view = view ?? DEFAULT_VIEW;
|
|
190
194
|
this.#boundOnAidaAvailabilityChange = this.#onAidaAvailabilityChange.bind(this);
|
|
191
195
|
this.#boundOnAiCodeCompletionSettingChanged = this.#onAiCodeCompletionSettingChanged.bind(this);
|
|
@@ -283,6 +287,11 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
|
283
287
|
|
|
284
288
|
if (result) {
|
|
285
289
|
this.#aiCodeCompletionFreCompletedSetting.set(true);
|
|
290
|
+
if (this.#panel === AiCodeCompletion.AiCodeCompletion.ContextFlavor.CONSOLE) {
|
|
291
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionFreCompletedFromConsole);
|
|
292
|
+
} else if (this.#panel === AiCodeCompletion.AiCodeCompletion.ContextFlavor.SOURCES) {
|
|
293
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionFreCompletedFromSources);
|
|
294
|
+
}
|
|
286
295
|
this.detach();
|
|
287
296
|
} else {
|
|
288
297
|
this.requestUpdate();
|
|
@@ -314,6 +314,9 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
|
|
|
314
314
|
jumpToFontPaletteDefinition(_paletteName: string): void {
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
jumpToCounterStyleDefinition(_counterStyleName: string): void {
|
|
318
|
+
}
|
|
319
|
+
|
|
317
320
|
jumpToDeclaration(_valueSource: SDK.CSSMatchedStyles.CSSValueSource): void {
|
|
318
321
|
}
|
|
319
322
|
|
|
@@ -1156,10 +1156,19 @@ export class LinkableNameRenderer extends rendererBase(SDK.CSSPropertyParserMatc
|
|
|
1156
1156
|
return {
|
|
1157
1157
|
jslogContext: 'css-font-palette',
|
|
1158
1158
|
metric: null,
|
|
1159
|
-
ruleBlock: '
|
|
1159
|
+
ruleBlock: '', // Not used
|
|
1160
1160
|
isDefined: Boolean(this.#matchedStyles.atRules().find(
|
|
1161
1161
|
ar => ar.type() === 'font-palette-values' && ar.name()?.text === match.text)),
|
|
1162
1162
|
};
|
|
1163
|
+
case SDK.CSSPropertyParserMatchers.LinkableNameProperties.LIST_STYLE:
|
|
1164
|
+
case SDK.CSSPropertyParserMatchers.LinkableNameProperties.LIST_STYLE_TYPE:
|
|
1165
|
+
return {
|
|
1166
|
+
jslogContext: 'css-list-style-type',
|
|
1167
|
+
metric: null,
|
|
1168
|
+
ruleBlock: '', // Not used
|
|
1169
|
+
isDefined: Boolean(this.#matchedStyles.atRules().find(
|
|
1170
|
+
ar => ar.type() === 'counter-style' && ar.name()?.text === match.text)),
|
|
1171
|
+
};
|
|
1163
1172
|
case SDK.CSSPropertyParserMatchers.LinkableNameProperties.POSITION_TRY:
|
|
1164
1173
|
case SDK.CSSPropertyParserMatchers.LinkableNameProperties.POSITION_TRY_FALLBACKS:
|
|
1165
1174
|
return {
|
|
@@ -1182,6 +1191,10 @@ export class LinkableNameRenderer extends rendererBase(SDK.CSSPropertyParserMatc
|
|
|
1182
1191
|
metric && Host.userMetrics.swatchActivated(metric);
|
|
1183
1192
|
if (match.propertyName === SDK.CSSPropertyParserMatchers.LinkableNameProperties.FONT_PALETTE) {
|
|
1184
1193
|
this.#stylesContainer.jumpToFontPaletteDefinition(match.text);
|
|
1194
|
+
} else if (
|
|
1195
|
+
match.propertyName === SDK.CSSPropertyParserMatchers.LinkableNameProperties.LIST_STYLE ||
|
|
1196
|
+
match.propertyName === SDK.CSSPropertyParserMatchers.LinkableNameProperties.LIST_STYLE_TYPE) {
|
|
1197
|
+
this.#stylesContainer.jumpToCounterStyleDefinition(match.text);
|
|
1185
1198
|
} else {
|
|
1186
1199
|
this.#stylesContainer.jumpToSectionBlock(`${ruleBlock} ${match.text}`);
|
|
1187
1200
|
}
|
|
@@ -3635,6 +3648,9 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
3635
3648
|
return;
|
|
3636
3649
|
}
|
|
3637
3650
|
this.#clearGhostTextInValue();
|
|
3651
|
+
if (this.value === text) {
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3638
3654
|
if (this.value) {
|
|
3639
3655
|
// If there is an existing value, and user is editing the name field
|
|
3640
3656
|
// which leads to a new value suggestion, then the previous value should no
|
|
@@ -3648,7 +3664,24 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
3648
3664
|
}
|
|
3649
3665
|
|
|
3650
3666
|
#clearGhostTextInValue(): void {
|
|
3651
|
-
this.listItemElement.querySelector('.ghost-value-prediction')
|
|
3667
|
+
const ghostTextElement = this.listItemElement.querySelector('.ghost-value-prediction');
|
|
3668
|
+
if (!ghostTextElement) {
|
|
3669
|
+
return;
|
|
3670
|
+
}
|
|
3671
|
+
ghostTextElement.remove();
|
|
3672
|
+
// If there's no value, there's nothing to restore
|
|
3673
|
+
if (!this.value) {
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
// Restore original classes
|
|
3677
|
+
if (this.property.parsedOk) {
|
|
3678
|
+
this.listItemElement.classList.remove('not-parsed-ok', 'invalid-property-value');
|
|
3679
|
+
} else {
|
|
3680
|
+
const invalidPropertyValue = SDK.CSSMetadata.cssMetadata().isCSSPropertyName(this.property.name);
|
|
3681
|
+
if (!invalidPropertyValue) {
|
|
3682
|
+
this.listItemElement.classList.remove('invalid-property-value');
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3652
3685
|
}
|
|
3653
3686
|
}
|
|
3654
3687
|
|
|
@@ -166,7 +166,7 @@ export class StylesAiCodeCompletionProvider {
|
|
|
166
166
|
}|null> {
|
|
167
167
|
this.#aiCodeCompletionConfig?.onRequestTriggered();
|
|
168
168
|
// Registering AiCodeCompletionRequestTriggered metric even if the request is served from cache
|
|
169
|
-
Host.userMetrics.actionTaken(Host.UserMetrics.Action.
|
|
169
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionRequestTriggeredFromStyles);
|
|
170
170
|
|
|
171
171
|
try {
|
|
172
172
|
const completionResponse = await this.#aiCodeCompletion?.completeCode(
|
|
@@ -52,6 +52,7 @@ export interface StylesContainer {
|
|
|
52
52
|
jumpToProperty(propertyName: string, sectionName?: string, blockName?: string): boolean;
|
|
53
53
|
jumpToSectionBlock(section: string): void;
|
|
54
54
|
jumpToFontPaletteDefinition(paletteName: string): void;
|
|
55
|
+
jumpToCounterStyleDefinition(counterStyleName: string): void;
|
|
55
56
|
jumpToDeclaration(valueSource: SDK.CSSMatchedStyles.CSSValueSource): void;
|
|
56
57
|
setActiveProperty(treeElement: StylePropertyTreeElement|null): void;
|
|
57
58
|
addStyleUpdateListener(listener: () => void): void;
|