chrome-devtools-frontend 1.0.1611390 → 1.0.1611825

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.
@@ -384,10 +384,15 @@ export interface FactualityMetadata {
384
384
  facts: FactualityFact[];
385
385
  }
386
386
 
387
+ export interface InferenceOptionMetadata {
388
+ modelId: string;
389
+ }
390
+
387
391
  export interface ResponseMetadata {
388
392
  rpcGlobalId?: RpcGlobalId;
389
393
  attributionMetadata?: AttributionMetadata;
390
394
  factualityMetadata?: FactualityMetadata;
395
+ inferenceOptionMetadata?: InferenceOptionMetadata;
391
396
  }
392
397
 
393
398
  export interface DoConversationResponse {
@@ -454,6 +454,7 @@ export function gcaChunkResponseToAidaChunkResponse(response: GCA.GenerateConten
454
454
  const parts = candidate?.content?.parts || [];
455
455
  const metadata: AIDA.ResponseMetadata = {
456
456
  rpcGlobalId: response.responseId,
457
+ inferenceOptionMetadata: {modelId: response.modelVersion}
457
458
  };
458
459
 
459
460
  if (candidate?.citationMetadata?.citations) {
@@ -858,7 +858,8 @@ export class ResourceTreeFrame {
858
858
  * https://chromium.googlesource.com/chromium/src/+/HEAD/docs/frame_trees.md
859
859
  */
860
860
  isPrimaryFrame(): boolean {
861
- return !this.#sameTargetParentFrame && this.#model.target() === TargetManager.instance().primaryPageTarget();
861
+ return !this.#sameTargetParentFrame &&
862
+ this.#model.target() === this.#model.target().targetManager().primaryPageTarget();
862
863
  }
863
864
 
864
865
  removeChildFrame(frame: ResourceTreeFrame, isSwap: boolean): void {
@@ -70,9 +70,7 @@ export class Target extends ProtocolClient.InspectorBackend.TargetBase {
70
70
  this.#capabilitiesMask = Capability.JS | Capability.LOG | Capability.NETWORK | Capability.TARGET |
71
71
  Capability.INSPECTOR | Capability.IO | Capability.EVENT_BREAKPOINTS;
72
72
  if (parentTarget?.type() !== Type.FRAME) {
73
- // TODO(crbug.com/406991275): This should also grant the `STORAGE` capability, but first the
74
- // crashers in https://crbug.com/466134219 have to be resolved.
75
- this.#capabilitiesMask |= Capability.BROWSER;
73
+ this.#capabilitiesMask |= Capability.BROWSER | Capability.STORAGE;
76
74
  }
77
75
  break;
78
76
  case Type.SHARED_WORKER:
@@ -895,7 +895,7 @@ inspectorBackend.registerCommand("Network.enableReportingApi", [{"name": "enable
895
895
  inspectorBackend.registerCommand("Network.enableDeviceBoundSessions", [{"name": "enable", "type": "boolean", "optional": false, "description": "Whether to enable or disable events.", "typeRef": null}], [], "Sets up tracking device bound sessions and fetching of initial set of sessions.");
896
896
  inspectorBackend.registerCommand("Network.fetchSchemefulSite", [{"name": "origin", "type": "string", "optional": false, "description": "The URL origin.", "typeRef": null}], ["schemefulSite"], "Fetches the schemeful site for a specific origin.");
897
897
  inspectorBackend.registerCommand("Network.loadNetworkResource", [{"name": "frameId", "type": "string", "optional": true, "description": "Frame id to get the resource for. Mandatory for frame targets, and should be omitted for worker targets.", "typeRef": "Page.FrameId"}, {"name": "url", "type": "string", "optional": false, "description": "URL of the resource to get content for.", "typeRef": null}, {"name": "options", "type": "object", "optional": false, "description": "Options for the request.", "typeRef": "Network.LoadNetworkResourceOptions"}], ["resource"], "Fetches the resource and returns the content.");
898
- inspectorBackend.registerCommand("Network.setCookieControls", [{"name": "enableThirdPartyCookieRestriction", "type": "boolean", "optional": false, "description": "Whether 3pc restriction is enabled.", "typeRef": null}, {"name": "disableThirdPartyCookieMetadata", "type": "boolean", "optional": false, "description": "Whether 3pc grace period exception should be enabled; false by default.", "typeRef": null}, {"name": "disableThirdPartyCookieHeuristics", "type": "boolean", "optional": false, "description": "Whether 3pc heuristics exceptions should be enabled; false by default.", "typeRef": null}], [], "Sets Controls for third-party cookie access Page reload is required before the new cookie behavior will be observed");
898
+ inspectorBackend.registerCommand("Network.setCookieControls", [{"name": "enableThirdPartyCookieRestriction", "type": "boolean", "optional": false, "description": "Whether 3pc restriction is enabled.", "typeRef": null}], [], "Sets Controls for third-party cookie access Page reload is required before the new cookie behavior will be observed");
899
899
  inspectorBackend.registerType("Network.ResourceTiming", [{"name": "requestTime", "type": "number", "optional": false, "description": "Timing's requestTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this requestTime.", "typeRef": null}, {"name": "proxyStart", "type": "number", "optional": false, "description": "Started resolving proxy.", "typeRef": null}, {"name": "proxyEnd", "type": "number", "optional": false, "description": "Finished resolving proxy.", "typeRef": null}, {"name": "dnsStart", "type": "number", "optional": false, "description": "Started DNS address resolve.", "typeRef": null}, {"name": "dnsEnd", "type": "number", "optional": false, "description": "Finished DNS address resolve.", "typeRef": null}, {"name": "connectStart", "type": "number", "optional": false, "description": "Started connecting to the remote host.", "typeRef": null}, {"name": "connectEnd", "type": "number", "optional": false, "description": "Connected to the remote host.", "typeRef": null}, {"name": "sslStart", "type": "number", "optional": false, "description": "Started SSL handshake.", "typeRef": null}, {"name": "sslEnd", "type": "number", "optional": false, "description": "Finished SSL handshake.", "typeRef": null}, {"name": "workerStart", "type": "number", "optional": false, "description": "Started running ServiceWorker.", "typeRef": null}, {"name": "workerReady", "type": "number", "optional": false, "description": "Finished Starting ServiceWorker.", "typeRef": null}, {"name": "workerFetchStart", "type": "number", "optional": false, "description": "Started fetch event.", "typeRef": null}, {"name": "workerRespondWithSettled", "type": "number", "optional": false, "description": "Settled fetch event respondWith promise.", "typeRef": null}, {"name": "workerRouterEvaluationStart", "type": "number", "optional": true, "description": "Started ServiceWorker static routing source evaluation.", "typeRef": null}, {"name": "workerCacheLookupStart", "type": "number", "optional": true, "description": "Started cache lookup when the source was evaluated to `cache`.", "typeRef": null}, {"name": "sendStart", "type": "number", "optional": false, "description": "Started sending request.", "typeRef": null}, {"name": "sendEnd", "type": "number", "optional": false, "description": "Finished sending request.", "typeRef": null}, {"name": "pushStart", "type": "number", "optional": false, "description": "Time the server started pushing request.", "typeRef": null}, {"name": "pushEnd", "type": "number", "optional": false, "description": "Time the server finished pushing request.", "typeRef": null}, {"name": "receiveHeadersStart", "type": "number", "optional": false, "description": "Started receiving response headers.", "typeRef": null}, {"name": "receiveHeadersEnd", "type": "number", "optional": false, "description": "Finished receiving response headers.", "typeRef": null}]);
900
900
  inspectorBackend.registerType("Network.PostDataEntry", [{"name": "bytes", "type": "string", "optional": true, "description": "", "typeRef": null}]);
901
901
  inspectorBackend.registerType("Network.Request", [{"name": "url", "type": "string", "optional": false, "description": "Request URL (without fragment).", "typeRef": null}, {"name": "urlFragment", "type": "string", "optional": true, "description": "Fragment of the requested URL starting with hash, if present.", "typeRef": null}, {"name": "method", "type": "string", "optional": false, "description": "HTTP request method.", "typeRef": null}, {"name": "headers", "type": "object", "optional": false, "description": "HTTP request headers.", "typeRef": "Network.Headers"}, {"name": "postData", "type": "string", "optional": true, "description": "HTTP POST request data. Use postDataEntries instead.", "typeRef": null}, {"name": "hasPostData", "type": "boolean", "optional": true, "description": "True when the request has POST data. Note that postData might still be omitted when this flag is true when the data is too long.", "typeRef": null}, {"name": "postDataEntries", "type": "array", "optional": true, "description": "Request body elements (post data broken into individual entries).", "typeRef": "Network.PostDataEntry"}, {"name": "mixedContentType", "type": "string", "optional": true, "description": "The mixed content type of the request.", "typeRef": "Security.MixedContentType"}, {"name": "initialPriority", "type": "string", "optional": false, "description": "Priority of the resource request at the time request is sent.", "typeRef": "Network.ResourcePriority"}, {"name": "referrerPolicy", "type": "string", "optional": false, "description": "The referrer policy of the request, as defined in https://www.w3.org/TR/referrer-policy/", "typeRef": null}, {"name": "isLinkPreload", "type": "boolean", "optional": true, "description": "Whether is loaded via link preload.", "typeRef": null}, {"name": "trustTokenParams", "type": "object", "optional": true, "description": "Set for requests when the TrustToken API is used. Contains the parameters passed by the developer (e.g. via \\\"fetch\\\") as understood by the backend.", "typeRef": "Network.TrustTokenParams"}, {"name": "isSameSite", "type": "boolean", "optional": true, "description": "True if this resource request is considered to be the 'same site' as the request corresponding to the main frame.", "typeRef": null}, {"name": "isAdRelated", "type": "boolean", "optional": true, "description": "True when the resource request is ad-related.", "typeRef": null}]);
@@ -3493,6 +3493,7 @@ export const generatedProperties = [
3493
3493
  {
3494
3494
  "keywords": [
3495
3495
  "auto",
3496
+ "chain",
3496
3497
  "contain",
3497
3498
  "none"
3498
3499
  ],
@@ -3501,6 +3502,7 @@ export const generatedProperties = [
3501
3502
  {
3502
3503
  "keywords": [
3503
3504
  "auto",
3505
+ "chain",
3504
3506
  "contain",
3505
3507
  "none"
3506
3508
  ],
@@ -6635,6 +6637,7 @@ export const generatedPropertyValues = {
6635
6637
  "overscroll-behavior-x": {
6636
6638
  "values": [
6637
6639
  "auto",
6640
+ "chain",
6638
6641
  "contain",
6639
6642
  "none"
6640
6643
  ]
@@ -6642,6 +6645,7 @@ export const generatedPropertyValues = {
6642
6645
  "overscroll-behavior-y": {
6643
6646
  "values": [
6644
6647
  "auto",
6648
+ "chain",
6645
6649
  "contain",
6646
6650
  "none"
6647
6651
  ]
@@ -12584,14 +12584,6 @@ export namespace Network {
12584
12584
  * Whether 3pc restriction is enabled.
12585
12585
  */
12586
12586
  enableThirdPartyCookieRestriction: boolean;
12587
- /**
12588
- * Whether 3pc grace period exception should be enabled; false by default.
12589
- */
12590
- disableThirdPartyCookieMetadata: boolean;
12591
- /**
12592
- * Whether 3pc heuristics exceptions should be enabled; false by default.
12593
- */
12594
- disableThirdPartyCookieHeuristics: boolean;
12595
12587
  }
12596
12588
 
12597
12589
  /**
@@ -7,7 +7,7 @@ import * as SDK from '../../core/sdk/sdk.js';
7
7
  import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
8
8
  import type * as Protocol from '../../generated/protocol.js';
9
9
  import * as Bindings from '../bindings/bindings.js';
10
- import type * as StackTrace from '../stack_trace/stack_trace.js';
10
+ import * as StackTrace from '../stack_trace/stack_trace.js';
11
11
 
12
12
  export const enum Events {
13
13
  TOOLS_ADDED = 'ToolsAdded',
@@ -16,16 +16,78 @@ export const enum Events {
16
16
  TOOL_RESPONDED = 'ToolResponded',
17
17
  }
18
18
 
19
+ export interface ExceptionDetails {
20
+ readonly error: SDK.RemoteObject.RemoteObject;
21
+ readonly description: string;
22
+ readonly frames: StackTrace.ErrorStackParser.ParsedErrorFrame[];
23
+ readonly cause?: ExceptionDetails;
24
+ }
25
+
26
+ export class Result {
27
+ readonly status: Protocol.WebMCP.InvocationStatus;
28
+ readonly output?: unknown;
29
+ readonly errorText?: string;
30
+ // TODO(crbug.com/494516094) Clean this up if the target disappears?
31
+ readonly #exception?: SDK.RemoteObject.RemoteObject;
32
+ #exceptionDetails?: Promise<ExceptionDetails|undefined>;
33
+
34
+ constructor(
35
+ status: Protocol.WebMCP.InvocationStatus, output: unknown|undefined, errorText: string|undefined,
36
+ exception: SDK.RemoteObject.RemoteObject|undefined) {
37
+ this.status = status;
38
+ this.errorText = errorText;
39
+ this.#exception = exception;
40
+ this.output = output;
41
+ }
42
+
43
+ get exceptionDetails(): Promise<ExceptionDetails|undefined>|undefined {
44
+ if (!this.#exceptionDetails) {
45
+ this.#exceptionDetails = this.#resolveExceptionDetails(this.#exception);
46
+ }
47
+ return this.#exceptionDetails;
48
+ }
49
+
50
+ async #resolveExceptionDetails(errorObj: SDK.RemoteObject.RemoteObject|undefined):
51
+ Promise<ExceptionDetails|undefined> {
52
+ if (!errorObj) {
53
+ return undefined;
54
+ }
55
+ const error = SDK.RemoteObject.RemoteError.objectAsError(errorObj);
56
+ const [details, cause] = await Promise.all([error.exceptionDetails(), error.cause()]);
57
+ const description = error.errorStack;
58
+
59
+ const frames =
60
+ StackTrace.ErrorStackParser.parseSourcePositionsFromErrorStack(errorObj.runtimeModel(), error.errorStack) || [];
61
+ if (details?.stackTrace) {
62
+ StackTrace.ErrorStackParser.augmentErrorStackWithScriptIds(frames, details.stackTrace);
63
+ }
64
+
65
+ if (cause?.subtype === 'error') {
66
+ return {error: errorObj, description, frames, cause: await this.#resolveExceptionDetails(cause)};
67
+ }
68
+
69
+ if (cause?.type === 'string') {
70
+ return {
71
+ error: errorObj,
72
+ description,
73
+ frames,
74
+ cause: {
75
+ error: cause,
76
+ description: cause.value as string,
77
+ frames: [],
78
+ }
79
+ };
80
+ }
81
+
82
+ return {error: errorObj, description, frames};
83
+ }
84
+ }
85
+
19
86
  export interface Call {
20
87
  invocationId: string;
21
88
  tool: Tool;
22
89
  input: string;
23
- result?: {
24
- status: Protocol.WebMCP.InvocationStatus,
25
- output?: unknown,
26
- errorText?: string,
27
- exception?: Protocol.Runtime.RemoteObject,
28
- };
90
+ result?: Result;
29
91
  }
30
92
 
31
93
  export class Tool {
@@ -160,11 +222,7 @@ export class WebMCPModel extends SDK.SDKModel.SDKModel<EventTypes> implements Pr
160
222
  if (!tool) {
161
223
  return;
162
224
  }
163
- const call: Call = {
164
- invocationId: params.invocationId,
165
- input: params.input,
166
- tool,
167
- };
225
+ const call: Call = {tool, input: params.input, invocationId: params.invocationId};
168
226
  this.#calls.set(params.invocationId, call);
169
227
  this.dispatchEventToListeners(Events.TOOL_INVOKED, call);
170
228
  }
@@ -174,12 +232,9 @@ export class WebMCPModel extends SDK.SDKModel.SDKModel<EventTypes> implements Pr
174
232
  if (!call) {
175
233
  return;
176
234
  }
177
- call.result = {
178
- status: params.status,
179
- output: params.output,
180
- errorText: params.errorText,
181
- exception: params.exception,
182
- };
235
+ const exception =
236
+ params.exception && this.target().model(SDK.RuntimeModel.RuntimeModel)?.createRemoteObject(params.exception);
237
+ call.result = new Result(params.status, params.output, params.errorText, exception);
183
238
  this.dispatchEventToListeners(Events.TOOL_RESPONDED, call);
184
239
  }
185
240
  }
@@ -306,9 +306,8 @@ async function getEmptyStateSuggestions(conversation?: AiAssistanceModel.AiConve
306
306
  ];
307
307
  case AiAssistanceModel.AiHistoryStorage.ConversationType.ACCESSIBILITY:
308
308
  return [
309
- {title: 'What are the accessibility issues on this page?', jslogContext: 'accessibility-default'},
310
- {title: 'How can I fix these accessibility issues?', jslogContext: 'accessibility-default'},
311
- {title: 'What does this Lighthouse report say about accessibility?', jslogContext: 'accessibility-default'},
309
+ {title: 'How can I fix accessibility issues on my page?', jslogContext: 'accessibility-default'},
310
+ {title: 'What accessibility issues exist on my page?', jslogContext: 'accessibility-default'},
312
311
  ];
313
312
  case AiAssistanceModel.AiHistoryStorage.ConversationType.NETWORK:
314
313
 
@@ -157,9 +157,13 @@ const UIStringsNotTranslate = {
157
157
  */
158
158
  completed: 'Completed',
159
159
  /**
160
- * @description Aria label for the cancel icon to be read by screen reader
160
+ * @description Aria label for the spinner to be read by screen reader when a step is in progress.
161
161
  */
162
- canceled: 'Canceled',
162
+ inProgress: 'In progress',
163
+ /**
164
+ * @description Aria label for the aborted icon to be read by screen reader
165
+ */
166
+ aborted: 'Aborted',
163
167
  /**
164
168
  * @description Alt text for the image input (displayed in the chat messages) that has been sent to the model.
165
169
  */
@@ -208,6 +212,10 @@ const UIStringsNotTranslate = {
208
212
  * @description Accessilility label for the button that shows the walkthrough when there are no widgets in the walkthrough.
209
213
  */
210
214
  showThinking: 'Show thinking',
215
+ /**
216
+ * @description Accessilility label for the button that hides the walkthrough when there are no widgets in the walkthrough.
217
+ */
218
+ hideThinking: 'Hide thinking',
211
219
  } as const;
212
220
 
213
221
  export interface Step {
@@ -467,7 +475,7 @@ function renderTitle(step: Step): Lit.LitTemplate {
467
475
  html`<span class="paused">${lockedString(UIStringsNotTranslate.paused)}: </span>` :
468
476
  Lit.nothing;
469
477
 
470
- return html`<span class="title">${paused}${titleForStep(step)}</span>`;
478
+ return html`<span class="title" aria-label=${titleForStep(step)}>${paused}${titleForStep(step)}</span>`;
471
479
  }
472
480
 
473
481
  function renderStepCode(step: Step): Lit.LitTemplate {
@@ -577,10 +585,10 @@ function renderWalkthroughSidebarButton(
577
585
  });
578
586
 
579
587
  let accessibleLabel = title;
580
- if (!isExpanded) {
581
- if (input.isLoading || lastStep.requestApproval) {
582
- accessibleLabel = `${titleForStep(lastStep)} ${i18n.i18n.lockedString(UIStringsNotTranslate.showThinking)}`;
583
- }
588
+ // If the agent is still thinking we want the accessibility label to include the current step title followed by Show/Hide thinking.
589
+ if (input.isLoading) {
590
+ const suffix = isExpanded ? UIStringsNotTranslate.hideThinking : UIStringsNotTranslate.showThinking;
591
+ accessibleLabel = `${titleForStep(lastStep)} ${i18n.i18n.lockedString(suffix)}`;
584
592
  }
585
593
 
586
594
  // clang-format off
@@ -683,7 +691,7 @@ function renderStepBadge({step, isLoading, isLast}: {
683
691
  isLast: boolean,
684
692
  }): Lit.LitTemplate {
685
693
  if (isLoading && isLast && !step.requestApproval) {
686
- return html`<devtools-spinner></devtools-spinner>`;
694
+ return html`<devtools-spinner aria-label=${lockedString(UIStringsNotTranslate.inProgress)}></devtools-spinner>`;
687
695
  }
688
696
 
689
697
  let iconName = 'checkmark';
@@ -691,10 +699,10 @@ function renderStepBadge({step, isLoading, isLast}: {
691
699
  let role: 'button'|undefined = 'button';
692
700
  if (isLast && step.requestApproval) {
693
701
  role = undefined;
694
- ariaLabel = undefined;
702
+ ariaLabel = lockedString(UIStringsNotTranslate.paused);
695
703
  iconName = 'pause-circle';
696
704
  } else if (step.canceled) {
697
- ariaLabel = lockedString(UIStringsNotTranslate.canceled);
705
+ ariaLabel = lockedString(UIStringsNotTranslate.aborted);
698
706
  iconName = 'cross';
699
707
  }
700
708
 
@@ -938,6 +946,7 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
938
946
  const revealButton = html`
939
947
  <devtools-button class="widget-reveal-button"
940
948
  .variant=${Buttons.Button.Variant.TEXT}
949
+ .accessibleLabel=${lockedString(UIStringsNotTranslate.reveal)}
941
950
  @click=${onReveal}
942
951
  >
943
952
  ${response.customRevealTitle ?? lockedString(UIStringsNotTranslate.reveal)}
@@ -950,7 +959,7 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
950
959
  <div class=${classes}>
951
960
  ${response.title ? html`
952
961
  <div class="widget-header">
953
- <div class="widget-name">${response.title}</div>
962
+ <h3 class="widget-name">${response.title}</h3>
954
963
  <div class="widget-reveal-container">
955
964
  ${revealButton}
956
965
  </div>
@@ -1255,6 +1264,7 @@ function renderActions(input: ChatMessageViewInput, output: ViewOutput): Lit.Lit
1255
1264
  .jslogContext=${'ai-export-for-agents'}
1256
1265
  .variant=${Buttons.Button.Variant.OUTLINED}
1257
1266
  .iconName=${'copy'}
1267
+ aria-label=${lockedString(UIStringsNotTranslate.exportForAgents)}
1258
1268
  @click=${input.onExportClick}
1259
1269
  >${lockedString(UIStringsNotTranslate.exportForAgents)}</devtools-button>
1260
1270
  ${input.suggestions ? html`<div class="vertical-separator"></div>` : Lit.nothing}
@@ -87,17 +87,18 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
87
87
  <style>${styles}</style>
88
88
  <div class="export-for-agents-dialog">
89
89
  <header>
90
- <h2 tabindex="-1">
90
+ <h1 id="export-for-agents-dialog-title" tabindex="-1">
91
91
  ${i18nString(UIStrings.exportForAgents)}
92
- </h2>
92
+ </h1>
93
93
  </header>
94
- <div class="state-selection">
94
+ <div class="state-selection" role="radiogroup" aria-labelledby="export-for-agents-dialog-title">
95
95
  <label>
96
96
  <input
97
97
  type="radio"
98
98
  value="prompt"
99
99
  name="export-state"
100
100
  .checked=${isPrompt}
101
+ aria-label=${i18nString(UIStrings.asPrompt)}
101
102
  @change=${() => input.onStateChange(StateType.PROMPT)}
102
103
  >
103
104
  ${i18nString(UIStrings.asPrompt)}
@@ -108,6 +109,7 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
108
109
  value="conversation"
109
110
  name="export-state"
110
111
  .checked=${!isPrompt}
112
+ aria-label=${i18nString(UIStrings.asMarkdown)}
111
113
  @change=${() => input.onStateChange(StateType.CONVERSATION)}
112
114
  >
113
115
  ${i18nString(UIStrings.asMarkdown)}
@@ -130,6 +132,7 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
130
132
  .jslogContext=${input.jslogContext}
131
133
  .variant=${Buttons.Button.Variant.PRIMARY}
132
134
  .disabled=${isPrompt && input.state.isPromptLoading}
135
+ .accessibleLabel=${buttonText}
133
136
  >
134
137
  ${buttonText}
135
138
  </devtools-button>
@@ -191,9 +194,10 @@ export class ExportForAgentsDialog extends UI.Widget.VBox {
191
194
  onButtonClick = (event: Event): void => {
192
195
  event.preventDefault();
193
196
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.#state.promptText);
194
- Snackbars.Snackbar.Snackbar.show({
197
+ const snackbar = Snackbars.Snackbar.Snackbar.show({
195
198
  message: i18nString(UIStrings.copiedToClipboard),
196
199
  });
200
+ snackbar.setAttribute('aria-label', i18nString(UIStrings.copiedToClipboard));
197
201
  this.#dialog.hide();
198
202
  };
199
203
  break;
@@ -45,6 +45,10 @@ const UIStrings = {
45
45
  * @description Title for the button that hides the walkthrough when there are widgets in the walkthrough.
46
46
  */
47
47
  hideAgentWalkthrough: 'Hide agent walkthrough',
48
+ /**
49
+ * @description Aria label for the spinner to be read by screen reader when a step is in progress.
50
+ */
51
+ inProgress: 'In progress',
48
52
  } as const;
49
53
  const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/components/WalkthroughView.ts', UIStrings);
50
54
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -118,7 +122,7 @@ function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate,
118
122
  <div class="inline-wrapper" ?data-open=${input.isExpanded}>
119
123
  <span class="inline-icon">
120
124
  ${input.isLoading ?
121
- html`<devtools-spinner></devtools-spinner>` :
125
+ html`<devtools-spinner aria-label=${lockedString(UIStrings.inProgress)}></devtools-spinner>` :
122
126
  html`<devtools-icon name=${icon}></devtools-icon>`
123
127
  }
124
128
  </span>
@@ -149,7 +153,7 @@ function renderSidebarWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate
149
153
  return html`
150
154
  <div class="walkthrough-view">
151
155
  <div class="walkthrough-header">
152
- <div class="walkthrough-title">${i18nString(UIStrings.title)}</div>
156
+ <h2 class="walkthrough-title">${i18nString(UIStrings.title)}</h2>
153
157
  <devtools-button
154
158
  .data=${{
155
159
  variant: Buttons.Button.Variant.TOOLBAR,
@@ -21,7 +21,7 @@
21
21
  .export-for-agents-dialog header {
22
22
  margin-bottom: var(--sys-size-6);
23
23
 
24
- h2 {
24
+ h1 {
25
25
  font: var(--sys-typescale-headline5);
26
26
  margin: 0;
27
27
  color: var(--sys-color-on-surface);
@@ -118,21 +118,9 @@
118
118
  &[open] {
119
119
  border-radius: var(--sys-size-5);
120
120
  width: auto;
121
- background-color: var(--sys-color-surface1);
121
+ background-color: var(--sys-color-surface2);
122
122
  margin-left: calc(var(--sys-size-6) / 2);
123
123
  flex-grow: 1;
124
-
125
- > summary {
126
- border-radius: var(--sys-shape-corner-medium-small);
127
- border-bottom-right-radius: 0;
128
- border-bottom-left-radius: 0;
129
- background: var(--sys-color-surface5);
130
- color: var(--sys-color-on-surface);
131
-
132
- &[data-has-widgets] {
133
- margin-left: 0;
134
- }
135
- }
136
124
  }
137
125
  }
138
126
 
@@ -177,6 +165,23 @@
177
165
  }
178
166
  }
179
167
 
168
+ .walkthrough-inline[open] > summary {
169
+ border-radius: var(--sys-shape-corner-medium-small);
170
+ border-bottom-right-radius: 0;
171
+ border-bottom-left-radius: 0;
172
+ background: var(--sys-color-surface5);
173
+ color: var(--sys-color-on-surface);
174
+
175
+ &[data-has-widgets] {
176
+ margin-left: 0;
177
+ }
178
+
179
+ > devtools-icon[name='chevron-right'] {
180
+ transform: rotate(270deg);
181
+ }
182
+
183
+ }
184
+
180
185
  .walkthrough-inline > summary::-webkit-details-marker {
181
186
  display: none;
182
187
  }
@@ -201,8 +206,4 @@
201
206
  .walkthrough-inline .step {
202
207
  background-color: var(--sys-color-surface5);
203
208
  }
204
-
205
- .walkthrough-inline[open] > summary > devtools-icon[name='chevron-right'] {
206
- transform: rotate(270deg);
207
- }
208
209
  }
@@ -433,19 +433,23 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
433
433
  @click=${() => input.onCallSelect(null)}
434
434
  ></devtools-button>
435
435
  <devtools-widget
436
- id="details"
436
+ id="webmcp.tool-details"
437
437
  title=${i18nString(UIStrings.toolDetails)}
438
438
  ${widget(ToolDetailsWidget, {tool: input.selectedCall?.tool})}>
439
439
  </devtools-widget>
440
440
  <devtools-widget
441
- id="inputs"
441
+ id="webmcp.call-inputs"
442
442
  title=${i18nString(UIStrings.input)}
443
443
  ${widget(PayloadWidget, parsePayload(input.selectedCall?.input))}>
444
444
  </devtools-widget>
445
445
  <devtools-widget
446
- id="outputs"
446
+ id="webmcp.call-outputs"
447
447
  title=${i18nString(UIStrings.output)}
448
- ${widget(PayloadWidget, parsePayload(input.selectedCall?.result?.output))}>
448
+ ${widget(PayloadWidget, {
449
+ valueObject: input.selectedCall?.result?.output,
450
+ errorText: input.selectedCall?.result?.errorText,
451
+ exceptionDetails: input.selectedCall?.result?.exceptionDetails,
452
+ })}>
449
453
  </devtools-widget>
450
454
  </devtools-tabbed-pane>
451
455
  </div>
@@ -685,10 +689,12 @@ export class WebMCPView extends UI.Widget.VBox {
685
689
  export interface PayloadViewInput {
686
690
  valueObject?: unknown;
687
691
  valueString?: string;
692
+ errorText?: string;
693
+ exceptionDetails?: WebMCP.WebMCPModel.ExceptionDetails;
688
694
  }
689
695
 
690
696
  export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, target: HTMLElement): void => {
691
- if (input.valueObject === undefined && input.valueString === undefined) {
697
+ if (!input.valueObject && !input.valueString && !input.errorText && !input.exceptionDetails) {
692
698
  render(nothing, target);
693
699
  return;
694
700
  }
@@ -715,6 +721,52 @@ export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, ta
715
721
  };
716
722
 
717
723
  const createSourceText = (text: string): TemplateResult => html`<div class="payload-value source-code">${text}</div>`;
724
+ const createErrorText = (text: string): TemplateResult =>
725
+ html`<div class="payload-value source-code error-text">${text}</div>`;
726
+
727
+ const createException = (
728
+ details: WebMCP.WebMCPModel.ExceptionDetails,
729
+ linkifier: Components.Linkifier.Linkifier = new Components.Linkifier.Linkifier(),
730
+ ): TemplateResult => {
731
+ const renderFrame = (
732
+ frame: StackTrace.ErrorStackParser.ParsedErrorFrame,
733
+ index: number,
734
+ array: StackTrace.ErrorStackParser.ParsedErrorFrame[],
735
+ ): TemplateResult => {
736
+ const newline = index < array.length - 1 ? '\n' : '';
737
+ const {line, link, isCallFrame} = frame;
738
+
739
+ if (!isCallFrame) {
740
+ return html`<span>${line}${newline}</span>`;
741
+ }
742
+
743
+ if (!link) {
744
+ return html`<span class="formatted-builtin-stack-frame">${line}${newline}</span>`;
745
+ }
746
+
747
+ const scriptLocationLink = linkifier.linkifyScriptLocation(
748
+ details.error.runtimeModel().target(),
749
+ link.scriptId || null,
750
+ link.url,
751
+ link.lineNumber,
752
+ {
753
+ columnNumber: link.columnNumber,
754
+ inlineFrameIndex: 0,
755
+ showColumnNumber: true,
756
+ },
757
+ );
758
+ scriptLocationLink.tabIndex = -1;
759
+
760
+ return html`<span class="formatted-stack-frame">${link.prefix}${scriptLocationLink}${link.suffix}${
761
+ newline}</span>`;
762
+ };
763
+
764
+ return html`
765
+ <div class="payload-value source-code error-text">
766
+ ${details.frames.length === 0 && details.description ? html`<span>${details.description}\n</span>` : nothing}
767
+ <div>${details.frames.map(renderFrame)}</div>
768
+ ${details.cause ? html`\nCaused by:\n${createException(details.cause, linkifier)}` : nothing}</div>`;
769
+ };
718
770
 
719
771
  render(
720
772
  html`
@@ -723,7 +775,10 @@ export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, ta
723
775
  <div class="call-payload-content">
724
776
  ${
725
777
  isParsable ? createPayload(input.valueObject) :
726
- (input.valueString !== undefined ? createSourceText(input.valueString) : nothing)}
778
+ (input.valueString !== undefined ?
779
+ createSourceText(input.valueString) :
780
+ (input.exceptionDetails ? createException(input.exceptionDetails) :
781
+ (input.errorText ? createErrorText(input.errorText) : nothing)))}
727
782
  </div>
728
783
  </div>
729
784
  `,
@@ -733,6 +788,9 @@ export const PAYLOAD_DEFAULT_VIEW = (input: PayloadViewInput, output: object, ta
733
788
  export class PayloadWidget extends UI.Widget.Widget {
734
789
  #valueObject?: unknown;
735
790
  #valueString?: string;
791
+ #errorText?: string;
792
+ #exceptionDetailsPromise?: Promise<WebMCP.WebMCPModel.ExceptionDetails|undefined>;
793
+ #exceptionDetails?: WebMCP.WebMCPModel.ExceptionDetails;
736
794
  #view: typeof PAYLOAD_DEFAULT_VIEW;
737
795
 
738
796
  constructor(element?: HTMLElement, view = PAYLOAD_DEFAULT_VIEW) {
@@ -758,6 +816,37 @@ export class PayloadWidget extends UI.Widget.Widget {
758
816
  return this.#valueString;
759
817
  }
760
818
 
819
+ set errorText(errorText: string|undefined) {
820
+ this.#errorText = errorText;
821
+ this.requestUpdate();
822
+ }
823
+
824
+ get errorText(): string|undefined {
825
+ return this.#errorText;
826
+ }
827
+
828
+ async #updateExceptionDetails(
829
+ exceptionDetailsPromise: Promise<WebMCP.WebMCPModel.ExceptionDetails|undefined>|undefined): Promise<void> {
830
+ if (this.#exceptionDetailsPromise === exceptionDetailsPromise) {
831
+ return;
832
+ }
833
+ this.#exceptionDetailsPromise = exceptionDetailsPromise;
834
+ this.#exceptionDetails = undefined;
835
+ this.requestUpdate();
836
+ const exceptionDetails = await exceptionDetailsPromise;
837
+ if (this.#exceptionDetailsPromise === exceptionDetailsPromise) {
838
+ this.#exceptionDetails = exceptionDetails;
839
+ this.requestUpdate();
840
+ }
841
+ }
842
+
843
+ set exceptionDetails(exceptionDetailsPromise: Promise<WebMCP.WebMCPModel.ExceptionDetails|undefined>|undefined) {
844
+ void this.#updateExceptionDetails(exceptionDetailsPromise);
845
+ }
846
+
847
+ get exceptionDetails(): Promise<WebMCP.WebMCPModel.ExceptionDetails|undefined>|undefined {
848
+ return this.#exceptionDetailsPromise;
849
+ }
761
850
  override wasShown(): void {
762
851
  super.wasShown();
763
852
  this.requestUpdate();
@@ -767,6 +856,8 @@ export class PayloadWidget extends UI.Widget.Widget {
767
856
  const input: PayloadViewInput = {
768
857
  valueObject: this.#valueObject,
769
858
  valueString: this.#valueString,
859
+ errorText: this.#errorText,
860
+ exceptionDetails: this.#exceptionDetails,
770
861
  };
771
862
  this.#view(input, {}, this.contentElement);
772
863
  }
@@ -48,7 +48,8 @@
48
48
  background-color: var(--sys-color-tonal-container);
49
49
  }
50
50
 
51
- tr.selected.status-error {
51
+ tbody tr.selected.status-error,
52
+ tbody tr.selected.status-error.revealed {
52
53
  background-color: var(--sys-color-error-container);
53
54
  color: var(--sys-color-error);
54
55
  }
@@ -210,4 +211,9 @@
210
211
  flex: auto;
211
212
  overflow: auto;
212
213
  }
214
+
215
+ .payload-value.error-text {
216
+ color: var(--sys-color-error);
217
+ white-space: pre-wrap;
218
+ }
213
219
  }
@@ -208,6 +208,12 @@ export class BreakpointEditDialog extends UI.Widget.Widget {
208
208
  this.requestUpdate();
209
209
  }
210
210
 
211
+ override focus(): void {
212
+ void this.updateComplete.then(() => {
213
+ this.#editor?.focus();
214
+ });
215
+ }
216
+
211
217
  override performUpdate(): void {
212
218
  const input: ViewInput = {
213
219
  state: this.#getEditorState(),
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: 295046833fe5ffe7765e09abf4e9c15980d09e76
4
+ Revision: ba9b7fcecd6da792b29305cac5a406adc76fc1e5
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -26,6 +26,11 @@ const UIStrings = {
26
26
  * @description The title of the button to copy the codeblock from a Markdown view.
27
27
  */
28
28
  copy: 'Copy code',
29
+ /**
30
+ * @description Accessible label for the button to copy the code block, referencing the specific content.
31
+ * @example {Data used} PH1
32
+ */
33
+ copyCodeSnippet: 'Copy {PH1} code snippet',
29
34
  /**
30
35
  * @description The title of the button after it was pressed and the text was copied to clipboard.
31
36
  */
@@ -242,6 +247,7 @@ export class CodeBlock extends HTMLElement {
242
247
  title: i18nString(UIStrings.copy),
243
248
  } as Buttons.Button.ButtonData
244
249
  }
250
+ .accessibleLabel=${this.#header ? i18nString(UIStrings.copyCodeSnippet, { PH1: this.#header }) : i18nString(UIStrings.copy)}
245
251
  @click=${this.#onCopy}
246
252
  ></devtools-button>
247
253
  ${this.#copied ? html`<span>${i18nString(UIStrings.copied)}</span>` : Lit.nothing}
@@ -4334,11 +4334,15 @@ export const knownContextValues = new Set([
4334
4334
  'webauthn.remove-credential',
4335
4335
  'webgl-error-fired',
4336
4336
  'webgl-warning-fired',
4337
+ 'webmcp.call-inputs',
4338
+ 'webmcp.call-outputs',
4337
4339
  'webmcp.declarative',
4338
4340
  'webmcp.error',
4339
4341
  'webmcp.imperative',
4340
4342
  'webmcp.pending',
4343
+ 'webmcp.status-types',
4341
4344
  'webmcp.success',
4345
+ 'webmcp.tool-details',
4342
4346
  'webp-format-disabled',
4343
4347
  'webp-format-disabled-true',
4344
4348
  'websocket',
package/mcp/mcp.ts CHANGED
@@ -28,7 +28,7 @@ export {Target} from '../front_end/core/sdk/Target.js';
28
28
  export {TargetManager} from '../front_end/core/sdk/TargetManager.js';
29
29
  export * as Foundation from '../front_end/foundation/foundation.js';
30
30
  export * as Protocol from '../front_end/generated/protocol.js';
31
- export {NetworkRequestFormatter} from '../front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js';
31
+ export * as NetworkRequestFormatter from '../front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js';
32
32
  export {
33
33
  PerformanceInsightFormatter
34
34
  } from '../front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js';
package/package.json CHANGED
@@ -104,5 +104,5 @@
104
104
  "flat-cache": "6.1.12"
105
105
  }
106
106
  },
107
- "version": "1.0.1611390"
107
+ "version": "1.0.1611825"
108
108
  }