chrome-devtools-frontend 1.0.1643855 → 1.0.1646286

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.
Files changed (95) hide show
  1. package/.agents/skills/devtools-source-maps/SKILL.md +124 -0
  2. package/docs/README.md +1 -0
  3. package/docs/using_source_maps.md +159 -0
  4. package/front_end/core/host/AidaClientTypes.ts +2 -0
  5. package/front_end/core/host/UserMetrics.ts +5 -3
  6. package/front_end/core/root/Runtime.ts +10 -0
  7. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
  8. package/front_end/core/sdk/DebuggerModel.ts +7 -9
  9. package/front_end/core/sdk/NetworkRequest.ts +0 -25
  10. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
  11. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  12. package/front_end/generated/SupportedCSSProperties.js +79 -2
  13. package/front_end/generated/protocol.ts +0 -5
  14. package/front_end/models/ai_assistance/AiAgent2.ts +52 -15
  15. package/front_end/models/ai_assistance/AiConversation.ts +4 -2
  16. package/front_end/models/ai_assistance/AiOrigins.ts +63 -2
  17. package/front_end/models/ai_assistance/README.md +20 -8
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  19. package/front_end/models/ai_assistance/agents/FileAgent.ts +9 -42
  20. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +2 -2
  21. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -133
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +25 -2
  23. package/front_end/models/ai_assistance/agents/README.md +64 -0
  24. package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
  25. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  26. package/front_end/models/ai_assistance/contexts/FileContext.ts +45 -0
  27. package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +48 -0
  28. package/front_end/models/ai_assistance/contexts/RequestContext.ts +116 -0
  29. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -1
  30. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +9 -12
  31. package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
  32. package/front_end/models/ai_assistance/tools/README.md +45 -0
  33. package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
  34. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
  35. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
  36. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
  37. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
  38. package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
  39. package/front_end/models/trace/Styles.ts +29 -7
  40. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
  41. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
  42. package/front_end/models/trace/helpers/Timing.ts +10 -0
  43. package/front_end/models/trace/types/TraceEvents.ts +22 -2
  44. package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
  45. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -15
  46. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  47. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
  48. package/front_end/panels/application/ApplicationPanelSidebar.ts +69 -0
  49. package/front_end/panels/application/ServiceWorkersView.ts +2 -2
  50. package/front_end/panels/application/WebMCPView.ts +40 -71
  51. package/front_end/panels/application/components/AdsView.ts +31 -28
  52. package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
  53. package/front_end/panels/application/components/adsView.css +6 -0
  54. package/front_end/panels/common/ExtensionServer.ts +5 -0
  55. package/front_end/panels/console/ConsoleView.ts +6 -1
  56. package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
  57. package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
  58. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
  59. package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
  60. package/front_end/panels/elements/PropertyRenderer.ts +0 -1
  61. package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
  62. package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
  63. package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
  64. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
  65. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
  66. package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
  67. package/front_end/panels/network/NetworkLogView.ts +34 -7
  68. package/front_end/panels/profiler/HeapProfileView.ts +0 -1
  69. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
  70. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  71. package/front_end/panels/profiler/IsolateSelector.ts +4 -2
  72. package/front_end/panels/profiler/ProfileLauncherView.ts +194 -126
  73. package/front_end/panels/profiler/ProfilesPanel.ts +1 -3
  74. package/front_end/panels/settings/components/SyncSection.ts +1 -1
  75. package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
  76. package/front_end/panels/timeline/TimelinePanel.ts +7 -0
  77. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
  78. package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
  79. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
  80. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
  81. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
  82. package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
  83. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
  84. package/front_end/third_party/chromium/README.chromium +1 -1
  85. package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
  86. package/front_end/ui/kit/link/Link.ts +16 -2
  87. package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
  88. package/front_end/ui/legacy/InspectorView.ts +4 -1
  89. package/front_end/ui/legacy/PlusButton.ts +6 -1
  90. package/front_end/ui/legacy/Widget.ts +19 -1
  91. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
  92. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
  93. package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
  94. package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
  95. package/package.json +1 -1
@@ -15,6 +15,8 @@ import type * as Trace from '../../trace/trace.js';
15
15
  import * as Workspace from '../../workspace/workspace.js';
16
16
  import {isOpaqueOrigin} from '../AiOrigins.js';
17
17
  import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
18
+ import {FileContext} from '../contexts/FileContext.js';
19
+ import {getRequestContextOrigin, RequestContext} from '../contexts/RequestContext.js';
18
20
  import {debugLog} from '../debug.js';
19
21
  import {StorageItem} from '../StorageItem.js';
20
22
 
@@ -26,8 +28,6 @@ import {
26
28
  type ContextResponse,
27
29
  type RequestOptions,
28
30
  } from './AiAgent.js';
29
- import {FileContext} from './FileAgent.js';
30
- import {getRequestContextOrigin, RequestContext} from './NetworkAgent.js';
31
31
  import {PerformanceTraceContext} from './PerformanceAgent.js';
32
32
  import {StorageContext} from './StorageAgent.js';
33
33
 
@@ -5,13 +5,11 @@
5
5
  import * as Host from '../../../core/host/host.js';
6
6
  import * as Root from '../../../core/root/root.js';
7
7
  import type * as Workspace from '../../workspace/workspace.js';
8
- import {FileFormatter} from '../data_formatters/FileFormatter.js';
9
8
 
10
9
  import {
11
10
  AiAgent,
12
- type ContextDetail,
13
11
  type ContextResponse,
14
- ConversationContext,
12
+ type ConversationContext,
15
13
  type RequestOptions,
16
14
  ResponseType,
17
15
  } from './AiAgent.js';
@@ -75,31 +73,6 @@ External Resources:
75
73
  MDN Web Docs: JavaScript Functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
76
74
  `;
77
75
 
78
- export class FileContext extends ConversationContext<Workspace.UISourceCode.UISourceCode> {
79
- #file: Workspace.UISourceCode.UISourceCode;
80
-
81
- constructor(file: Workspace.UISourceCode.UISourceCode) {
82
- super();
83
- this.#file = file;
84
- }
85
-
86
- override getURL(): string {
87
- return this.#file.url();
88
- }
89
-
90
- override getItem(): Workspace.UISourceCode.UISourceCode {
91
- return this.#file;
92
- }
93
-
94
- override getTitle(): string {
95
- return this.#file.displayName();
96
- }
97
-
98
- override async refresh(): Promise<void> {
99
- await this.#file.requestContentData();
100
- }
101
- }
102
-
103
76
  /**
104
77
  * One agent instance handles one conversation. Create a new agent
105
78
  * instance for a new conversation.
@@ -126,27 +99,21 @@ export class FileAgent extends AiAgent<Workspace.UISourceCode.UISourceCode> {
126
99
  return;
127
100
  }
128
101
 
102
+ const details = await selectedFile.getUserFacingDetails();
103
+ if (!details) {
104
+ return;
105
+ }
106
+
129
107
  yield {
130
108
  type: ResponseType.CONTEXT,
131
- details: createContextDetailsForFileAgent(selectedFile),
109
+ details,
132
110
  };
133
111
  }
134
112
 
135
113
  override async enhanceQuery(
136
114
  query: string, selectedFile: ConversationContext<Workspace.UISourceCode.UISourceCode>|null): Promise<string> {
137
- const fileEnchantmentQuery = selectedFile ?
138
- `# Selected file\n${new FileFormatter(selectedFile.getItem()).formatFile()}\n\n# User request\n\n` :
139
- '';
115
+ const promptDetails = selectedFile ? await selectedFile.getPromptDetails() : null;
116
+ const fileEnchantmentQuery = promptDetails ? `${promptDetails}\n\n# User request\n\n` : '';
140
117
  return `${fileEnchantmentQuery}${query}`;
141
118
  }
142
119
  }
143
-
144
- function createContextDetailsForFileAgent(selectedFile: ConversationContext<Workspace.UISourceCode.UISourceCode>):
145
- [ContextDetail, ...ContextDetail[]] {
146
- return [
147
- {
148
- title: 'Selected file',
149
- text: new FileFormatter(selectedFile.getItem()).formatFile(),
150
- },
151
- ];
152
- }
@@ -10,7 +10,7 @@ Content:
10
10
  },
11
11
  {
12
12
  "title": "Response",
13
- "text": "Response headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200 \nNetwork request status: pending\n"
13
+ "text": "Response headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200\nNetwork request status: pending\n"
14
14
  },
15
15
  {
16
16
  "title": "Timing",
@@ -59,7 +59,7 @@ Content:
59
59
  {
60
60
  "parts": [
61
61
  {
62
- "text": "# Selected network request \nRequest: https://www.example.com\n\nRequest headers:\ncontent-type: bar1\n\nResponse headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200 \nNetwork request status: pending\n\nRequest timing:\nQueued at (timestamp): 0 s\nStarted at (timestamp): 501 s\nQueueing (duration): 501 s\nConnection start (stalled) (duration): 800 ms\nRequest sent (duration): 100 ms\nDuration (duration): 501 s\n\nRequest initiator chain:\n- URL: <redacted cross-origin initiator URL>\n\t- URL: https://www.example.com\n\t\t- URL: https://www.example.com/1\n\t\t- URL: https://www.example.com/2\n\n# User request\n\ntest"
62
+ "text": "# Selected network request\nRequest: https://www.example.com\n\nRequest headers:\ncontent-type: bar1\n\nResponse headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200\nNetwork request status: pending\n\nRequest timing:\nQueued at (timestamp): 0 s\nStarted at (timestamp): 501 s\nQueueing (duration): 501 s\nConnection start (stalled) (duration): 800 ms\nRequest sent (duration): 100 ms\nDuration (duration): 501 s\n\nRequest initiator chain:\n- URL: <redacted cross-origin initiator URL>\n\t- URL: https://www.example.com\n\t\t- URL: https://www.example.com/1\n\t\t- URL: https://www.example.com/2\n\n# User request\n\ntest"
63
63
  }
64
64
  ],
65
65
  "role": 1
@@ -2,21 +2,14 @@
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 * as Common from '../../../core/common/common.js';
6
5
  import * as Host from '../../../core/host/host.js';
7
- import * as i18n from '../../../core/i18n/i18n.js';
8
- import type * as Platform from '../../../core/platform/platform.js';
9
6
  import * as Root from '../../../core/root/root.js';
10
7
  import type * as SDK from '../../../core/sdk/sdk.js';
11
- import type * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
12
- import {extractContextOrigin} from '../AiOrigins.js';
13
- import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
8
+ import type {RequestContext} from '../contexts/RequestContext.js';
14
9
 
15
10
  import {
16
11
  AiAgent,
17
- type ContextDetail,
18
12
  type ContextResponse,
19
- ConversationContext,
20
13
  type RequestOptions,
21
14
  ResponseType,
22
15
  } from './AiAgent.js';
@@ -73,90 +66,6 @@ This request aims to retrieve a list of products matching the search query "lapt
73
66
  `;
74
67
  /* clang-format on */
75
68
 
76
- /*
77
- * Strings that don't need to be translated at this time.
78
- */
79
- const UIStringsNotTranslate = {
80
- /**
81
- * @description Heading text for the block that shows the network request details.
82
- */
83
- request: 'Request',
84
- /**
85
- * @description Heading text for the block that shows the network response details.
86
- */
87
- response: 'Response',
88
- /**
89
- * @description Prefix text for request URL.
90
- */
91
- requestUrl: 'Request URL',
92
- /**
93
- * @description Title text for request timing details.
94
- */
95
- timing: 'Timing',
96
- /**
97
- * @description Title text for request initiator chain.
98
- */
99
- requestInitiatorChain: 'Request initiator chain',
100
- } as const;
101
-
102
- const lockedString = i18n.i18n.lockedString;
103
-
104
- /**
105
- * Returns the origin for a network request in the AI context.
106
- *
107
- * To prevent cross-origin prompt injection attacks, HAR-imported requests
108
- * are isolated from live pages. We assign them a virtual origin
109
- * (`imported-har://${domain}`) so they do not share the origin of live pages
110
- * (e.g., `https://${domain}`). This forces a conversation reset when transitioning
111
- * between imported HAR data and live pages.
112
- */
113
- export function getRequestContextOrigin(request: SDK.NetworkRequest.NetworkRequest): string {
114
- const origin = extractContextOrigin(request.documentURL);
115
- if (request.isImportedHar()) {
116
- const parsed = Common.ParsedURL.ParsedURL.fromString(origin as Platform.DevToolsPath.UrlString);
117
- return `imported-har://${parsed ? parsed.domain() : origin}`;
118
- }
119
- return origin;
120
- }
121
-
122
- export class RequestContext extends ConversationContext<SDK.NetworkRequest.NetworkRequest> {
123
- #request: SDK.NetworkRequest.NetworkRequest;
124
- #calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
125
-
126
- constructor(
127
- request: SDK.NetworkRequest.NetworkRequest, calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator) {
128
- super();
129
- this.#request = request;
130
- this.#calculator = calculator;
131
- }
132
-
133
- /**
134
- * Note: this is not the literal origin of the network request. This URL
135
- * is used to determine when we should force the user to start a new AI
136
- * conversation when the context changes. We allow a single AI conversation to
137
- * inspect all network requests that were made for that given target URL.
138
- */
139
- override getURL(): string {
140
- return this.#request.documentURL;
141
- }
142
-
143
- override getOrigin(): string {
144
- return getRequestContextOrigin(this.#request);
145
- }
146
-
147
- override getItem(): SDK.NetworkRequest.NetworkRequest {
148
- return this.#request;
149
- }
150
-
151
- get calculator(): NetworkTimeCalculator.NetworkTimeCalculator {
152
- return this.#calculator;
153
- }
154
-
155
- override getTitle(): string {
156
- return this.#request.name();
157
- }
158
- }
159
-
160
69
  /**
161
70
  * One agent instance handles one conversation. Create a new agent
162
71
  * instance for a new conversation.
@@ -183,9 +92,14 @@ export class NetworkAgent extends AiAgent<SDK.NetworkRequest.NetworkRequest> {
183
92
  return;
184
93
  }
185
94
 
95
+ const details = await selectedNetworkRequest.getUserFacingDetails();
96
+ if (!details) {
97
+ return;
98
+ }
99
+
186
100
  yield {
187
101
  type: ResponseType.CONTEXT,
188
- details: await createContextDetailsForNetworkAgent(selectedNetworkRequest),
102
+ details,
189
103
  widgets: [{
190
104
  name: 'NETWORK_REQUEST_GENERAL_HEADERS',
191
105
  data: {
@@ -196,46 +110,8 @@ export class NetworkAgent extends AiAgent<SDK.NetworkRequest.NetworkRequest> {
196
110
  }
197
111
 
198
112
  override async enhanceQuery(query: string, selectedNetworkRequest: RequestContext|null): Promise<string> {
199
- const networkEnchantmentQuery = selectedNetworkRequest ?
200
- `# Selected network request \n${
201
- await (new NetworkRequestFormatter(selectedNetworkRequest.getItem(), selectedNetworkRequest.calculator)
202
- .formatNetworkRequest())}\n\n# User request\n\n` :
203
- '';
113
+ const promptDetails = selectedNetworkRequest ? await selectedNetworkRequest.getPromptDetails() : null;
114
+ const networkEnchantmentQuery = promptDetails ? `${promptDetails}\n\n# User request\n\n` : '';
204
115
  return `${networkEnchantmentQuery}${query}`;
205
116
  }
206
117
  }
207
-
208
- async function createContextDetailsForNetworkAgent(
209
- selectedNetworkRequest: RequestContext,
210
- ): Promise<[ContextDetail, ...ContextDetail[]]> {
211
- const request = selectedNetworkRequest.getItem();
212
- const formatter = new NetworkRequestFormatter(request, selectedNetworkRequest.calculator);
213
- const requestContextDetail: ContextDetail = {
214
- title: lockedString(UIStringsNotTranslate.request),
215
- text: lockedString(UIStringsNotTranslate.requestUrl) + ': ' + request.url() + '\n\n' +
216
- formatter.formatRequestHeaders(),
217
- };
218
- const responseBody = await formatter.formatResponseBody();
219
- const responseBodyString = responseBody ? `\n\n${responseBody}` : '';
220
-
221
- const responseContextDetail: ContextDetail = {
222
- title: lockedString(UIStringsNotTranslate.response),
223
- text: formatter.formatResponseHeaders() + responseBodyString +
224
- `\n\n${formatter.formatStatus()}${formatter.formatFailureReasons()}`,
225
- };
226
- const timingContextDetail: ContextDetail = {
227
- title: lockedString(UIStringsNotTranslate.timing),
228
- text: formatter.formatNetworkRequestTiming(),
229
- };
230
- const initiatorChainContextDetail: ContextDetail = {
231
- title: lockedString(UIStringsNotTranslate.requestInitiatorChain),
232
- text: formatter.formatRequestInitiatorChain(),
233
- };
234
-
235
- return [
236
- requestContextDetail,
237
- responseContextDetail,
238
- timingContextDetail,
239
- initiatorChainContextDetail,
240
- ];
241
- }
@@ -15,7 +15,7 @@ import * as Logs from '../../logs/logs.js';
15
15
  import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
16
16
  import * as TextUtils from '../../text_utils/text_utils.js';
17
17
  import * as Trace from '../../trace/trace.js';
18
- import {extractContextOrigin} from '../AiOrigins.js';
18
+ import {canResourceContentsBeReadForTrace, extractContextOrigin} from '../AiOrigins.js';
19
19
  import {sanitizeHeaders} from '../data_formatters/NetworkRequestFormatter.js';
20
20
  import {
21
21
  PerformanceInsightFormatter,
@@ -751,11 +751,26 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
751
751
  yield* super.run(initialQuery, options);
752
752
  }
753
753
 
754
+ /**
755
+ * Clears performance-agent-specific caches and state.
756
+ * This is called when the conversation needs to be reset (e.g. on navigation)
757
+ * to prevent stale formatters, trace facts, or selection contexts from leaking
758
+ * into subsequent runs.
759
+ */
754
760
  override clearCache(): void {
761
+ super.clearCache();
755
762
  // Clear the function call cache to prevent stashed tool execution results
756
763
  // (which might contain cross-origin resource content fetched before navigation
757
764
  // was detected) from being replayed as facts in subsequent runs.
758
765
  this.#functionCallCacheForFocus.clear();
766
+ // Reset the formatter and trace facts so they are recreated with the
767
+ // correct target and origin on the next execution.
768
+ this.#formatter = null;
769
+ this.#traceFacts = [];
770
+ this.#lastEventForEnhancedQuery = undefined;
771
+ this.#lastInsightForEnhancedQuery = undefined;
772
+ this.#additionalSelectionsForDisclosure = [];
773
+ this.#callTreeContextSet = new WeakSet();
759
774
  }
760
775
 
761
776
  #createFactForTraceSummary(): void {
@@ -1457,8 +1472,16 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1457
1472
  },
1458
1473
  handler: async args => {
1459
1474
  debugLog('Function call: getResourceContent');
1475
+ if (!isFresh) {
1476
+ return {error: 'Cannot use this tool on an imported file.'};
1477
+ }
1478
+
1479
+ const url = args.url;
1480
+ const allowedOrigin = context.getOrigin();
1481
+ if (!canResourceContentsBeReadForTrace(url, allowedOrigin)) {
1482
+ return {error: 'Resource not found'};
1483
+ }
1460
1484
 
1461
- const url = args.url as Platform.DevToolsPath.UrlString;
1462
1485
  let content: string|undefined;
1463
1486
 
1464
1487
  // First check parsedTrace.data.Scripts.
@@ -2,6 +2,42 @@
2
2
 
3
3
  This directory contains the implementations of various AI agents used in the AI Assistance panel in Chrome DevTools.
4
4
 
5
+ ## Agent Lifecycle & State Management
6
+
7
+ AI Agents can maintain internal stateful variables to optimize performance or store context (e.g., stashed tool results, formatters, or instruction flags). However, this state must be carefully managed to prevent security leaks (such as cross-origin data leaks after page navigation) or stale results.
8
+
9
+ ### Cache Clearing (`clearCache()`)
10
+
11
+ The `AiAgent` base class defines a `clearCache()` method. This method is automatically invoked by the system when:
12
+ - An execution error occurs.
13
+ - The user aborts the execution.
14
+ - A cross-origin navigation is detected (via the top-level origin blocking mechanism).
15
+
16
+ #### Overriding `clearCache()` in Subclasses
17
+
18
+ If you introduce new stateful member variables in an `AiAgent` subclass, you **must** override `clearCache()` to reset them:
19
+
20
+ 1. Always call `super.clearCache()` to ensure base class cleanup is executed.
21
+ 2. Reset any subclass-specific state (e.g., setting formatters to `null`, clearing lists, resetting boolean flags).
22
+
23
+ Example from `PerformanceAgent`:
24
+ ```typescript
25
+ override clearCache(): void {
26
+ super.clearCache();
27
+ this.#functionCallCacheForFocus.clear();
28
+ this.#formatter = null;
29
+ this.#traceFacts = [];
30
+ // ... reset other stateful fields
31
+ }
32
+ ```
33
+
34
+ ### Origin Validation (`isOriginAllowed`)
35
+
36
+ Before running an execution loop, the system validates the context's origin:
37
+ * **Opaque Origin Rejection**: Opaque origins are rejected immediately, blocking conversations on untrusted/opaque contexts (like `about:blank`, `data:` URLs, or opaque blob URLs).
38
+ * **Origin Lock Integrity**: If the conversation is already locked to an origin, the new context's origin must be equivalent (as defined by `areOriginsEquivalent()`) to the locked origin.
39
+ * **Safety Termination**: If validation fails, a cross-origin error is yielded and execution stops.
40
+
5
41
  ## Performance Agent
6
42
 
7
43
  The `PerformanceAgent` analyzes performance traces. This documentation details the specific data provided to the agent and the data it can retrieve via functions.
@@ -70,3 +106,31 @@ The agent can request additional data by calling functions. Here is the data the
70
106
  #### `selectEventByKey`
71
107
  - **Arguments**: `eventKey` (string)
72
108
  - **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function also modifies the DevTools UI by selecting the event in the flamechart).
109
+
110
+ ## Styling Agent
111
+
112
+ The `StylingAgent` assists with CSS styling and layout questions. It can interact with the page to inspect styles, execute Javascript, and optionally emulate devices or vision deficiencies.
113
+
114
+ ### Initial Data Provided to the Agent
115
+
116
+ The agent is initialized with the selected DOM node context.
117
+
118
+ ### Data Retrieval & Action Functions (Tools)
119
+
120
+ The agent can call the following functions to retrieve more details or perform actions:
121
+
122
+ #### `getStyles`
123
+ - **Arguments**: None (it uses the currently selected DOM node).
124
+ - **Data Returned to Agent**: Computed styles and authored styles (matching rules, active stylesheets, etc.) for the selected node.
125
+
126
+ #### `executeJavaScript`
127
+ - **Arguments**: `query` (string)
128
+ - **Data Returned to Agent**: The result of executing the JavaScript query in the context of the page.
129
+
130
+ #### `addElementAnnotation`
131
+ - **Arguments**: `elementId` (string), `annotationMessage` (string)
132
+ - **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function also modifies the DevTools UI by adding a visual annotation to the node).
133
+
134
+ #### `activateDeviceEmulation`
135
+ - **Arguments**: `deviceName` (string), `visionDeficiency` (string, optional)
136
+ - **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function modifies the DevTools UI by enabling device and/or vision deficiency emulation).
@@ -191,9 +191,18 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
191
191
  description: getStylesTool.description,
192
192
  parameters: getStylesTool.parameters,
193
193
  displayInfoFromArgs: getStylesTool.displayInfoFromArgs,
194
- handler: args => getStylesTool.handler(args, {
195
- conversationContext: this.context ?? null,
196
- }),
194
+ handler: async args => {
195
+ const context = this.context;
196
+ if (!context) {
197
+ return {error: 'Error: Could not find the currently selected element.'};
198
+ }
199
+ return await getStylesTool.handler(args, {
200
+ conversationContext: context,
201
+ getTarget: () =>
202
+ SDK.TargetManager.TargetManager.instance().primaryPageTarget() ?? context.getItem().domModel().target(),
203
+ getEstablishedOrigin: () => context.getOrigin(),
204
+ });
205
+ },
197
206
  });
198
207
 
199
208
  const executeJsTool = ToolRegistry.get(ToolName.EXECUTE_JAVASCRIPT);
@@ -281,6 +290,20 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
281
290
  });
282
291
  }
283
292
 
293
+ /**
294
+ * Clears styling-agent-specific caches and state.
295
+ * Resets cached emulation data (screenshots, accessibility tree) and the
296
+ * instructions flag to ensure they are re-evaluated in subsequent queries.
297
+ */
298
+ override clearCache(): void {
299
+ super.clearCache();
300
+ // Reset emulation state so that subsequent queries will re-initialize
301
+ // emulation details and fetch fresh data.
302
+ this.#greenDevEmulationScreenshot = null;
303
+ this.#greenDevEmulationAxTree = null;
304
+ this.#hasAddedEmulationInstructions = false;
305
+ }
306
+
284
307
  override preambleFeatures(): string[] {
285
308
  return ['function_calling'];
286
309
  }
@@ -23,6 +23,8 @@ import * as AiUtils from './AiUtils.js';
23
23
  import * as BuiltInAi from './BuiltInAi.js';
24
24
  import * as ChangeManager from './ChangeManager.js';
25
25
  import * as DOMNodeContext from './contexts/DOMNodeContext.js';
26
+ import * as FileContext from './contexts/FileContext.js';
27
+ import * as RequestContext from './contexts/RequestContext.js';
26
28
  import * as ConversationSummary from './ConversationSummary.js';
27
29
  import * as FileFormatter from './data_formatters/FileFormatter.js';
28
30
  import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
@@ -66,6 +68,7 @@ export {
66
68
  ExecuteJavaScript,
67
69
  ExtensionScope,
68
70
  FileAgent,
71
+ FileContext,
69
72
  FileFormatter,
70
73
  GetStyles,
71
74
  GreenDevAgent,
@@ -80,6 +83,7 @@ export {
80
83
  PerformanceAnnotations,
81
84
  PerformanceInsightFormatter,
82
85
  PerformanceTraceFormatter,
86
+ RequestContext,
83
87
  StorageAgent,
84
88
  StorageItem,
85
89
  StylingAgent,
@@ -0,0 +1,45 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import type * as Workspace from '../../workspace/workspace.js';
6
+ import {type ContextDetail, ConversationContext} from '../agents/AiAgent.js';
7
+ import {FileFormatter} from '../data_formatters/FileFormatter.js';
8
+
9
+ export class FileContext extends ConversationContext<Workspace.UISourceCode.UISourceCode> {
10
+ #file: Workspace.UISourceCode.UISourceCode;
11
+
12
+ constructor(file: Workspace.UISourceCode.UISourceCode) {
13
+ super();
14
+ this.#file = file;
15
+ }
16
+
17
+ override getURL(): string {
18
+ return this.#file.url();
19
+ }
20
+
21
+ override getItem(): Workspace.UISourceCode.UISourceCode {
22
+ return this.#file;
23
+ }
24
+
25
+ override getTitle(): string {
26
+ return this.#file.displayName();
27
+ }
28
+
29
+ override async getPromptDetails(): Promise<string|null> {
30
+ return `# Selected file\n${new FileFormatter(this.#file).formatFile()}`;
31
+ }
32
+
33
+ override async getUserFacingDetails(): Promise<[ContextDetail, ...ContextDetail[]]|null> {
34
+ return [
35
+ {
36
+ title: 'Selected file',
37
+ text: new FileFormatter(this.#file).formatFile(),
38
+ },
39
+ ];
40
+ }
41
+
42
+ override async refresh(): Promise<void> {
43
+ await this.#file.requestContentData();
44
+ }
45
+ }
@@ -0,0 +1,48 @@
1
+ Title: RequestContext getPromptDetails describes the network request correctly
2
+ Content:
3
+ # Selected network request
4
+ Request: https://www.example.com/api/users
5
+
6
+ Request headers:
7
+ Accept: application/json
8
+
9
+ Response headers:
10
+ Content-Type: application/json
11
+
12
+ Response body:
13
+ {}
14
+
15
+ Response status: 200
16
+ Network request status: pending
17
+
18
+ Request timing:
19
+ Queued at (timestamp): 0 s
20
+ Started at (timestamp): 0 s
21
+ Connection start (stalled) (duration): -
22
+ Duration (duration): -
23
+
24
+ Request initiator chain:
25
+ - URL: https://www.example.com/api/users
26
+ === end content
27
+
28
+ Title: RequestContext getUserFacingDetails returns details correctly
29
+ Content:
30
+ [
31
+ {
32
+ "title": "Request",
33
+ "text": "Request URL: https://www.example.com/api/users\n\nRequest headers:\nAccept: application/json"
34
+ },
35
+ {
36
+ "title": "Response",
37
+ "text": "Response headers:\nContent-Type: application/json\n\nResponse body:\n{}\n\nResponse status: 200\nNetwork request status: pending\n"
38
+ },
39
+ {
40
+ "title": "Timing",
41
+ "text": "Queued at (timestamp): 0 s\nStarted at (timestamp): 0 s\nConnection start (stalled) (duration): -\nDuration (duration): -"
42
+ },
43
+ {
44
+ "title": "Request initiator chain",
45
+ "text": "- URL: https://www.example.com/api/users"
46
+ }
47
+ ]
48
+ === end content