chrome-devtools-frontend 1.0.1642899 → 1.0.1643855

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 (125) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/extension-api/ExtensionAPI.d.ts +83 -12
  3. package/front_end/core/host/UserMetrics.ts +0 -1
  4. package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
  5. package/front_end/core/root/ExperimentNames.ts +0 -1
  6. package/front_end/core/sdk/ConsoleModel.ts +4 -0
  7. package/front_end/core/sdk/NetworkRequest.ts +12 -0
  8. package/front_end/core/sdk/SourceMap.ts +15 -18
  9. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
  10. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
  11. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +4 -5
  12. package/front_end/entrypoints/main/MainImpl.ts +0 -6
  13. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  14. package/front_end/generated/protocol.ts +7 -0
  15. package/front_end/models/ai_assistance/AiAgent2.ts +24 -5
  16. package/front_end/models/ai_assistance/AiConversation.ts +15 -12
  17. package/front_end/models/ai_assistance/AiUtils.ts +71 -0
  18. package/front_end/models/ai_assistance/ChangeManager.ts +2 -5
  19. package/front_end/models/ai_assistance/{agents/ConversationSummaryAgent.ts → ConversationSummary.ts} +29 -66
  20. package/front_end/models/ai_assistance/ExtensionScope.ts +1 -4
  21. package/front_end/models/ai_assistance/{agents/PerformanceAnnotationsAgent.ts → PerformanceAnnotations.ts} +47 -89
  22. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +47 -31
  23. package/front_end/models/ai_assistance/agents/AiAgent.ts +40 -12
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +11 -0
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +58 -8
  26. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -92
  27. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +25 -0
  28. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +94 -79
  29. package/front_end/models/ai_assistance/agents/StorageAgent.ts +101 -39
  30. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -2
  31. package/front_end/models/ai_assistance/agents/StylingAgent.ts +27 -21
  32. package/front_end/models/ai_assistance/ai_assistance.ts +6 -4
  33. package/front_end/models/ai_assistance/skills/styling.md +12 -4
  34. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +134 -0
  35. package/front_end/models/ai_assistance/tools/GetStyles.ts +6 -2
  36. package/front_end/models/ai_assistance/tools/Tool.ts +16 -1
  37. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +2 -0
  38. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -9
  39. package/front_end/models/bindings/DefaultScriptMapping.ts +2 -1
  40. package/front_end/models/bindings/SymbolizedError.ts +45 -35
  41. package/front_end/models/extensions/ExtensionAPI.ts +138 -47
  42. package/front_end/models/har/Importer.ts +1 -0
  43. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -7
  44. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -2
  45. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +44 -51
  46. package/front_end/models/stack_trace/StackTrace.ts +7 -0
  47. package/front_end/models/stack_trace/StackTraceImpl.ts +13 -4
  48. package/front_end/models/stack_trace/StackTraceModel.ts +9 -8
  49. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +2 -1
  50. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -8
  51. package/front_end/panels/ai_assistance/components/ChatMessage.ts +96 -4
  52. package/front_end/panels/ai_assistance/components/chatMessage.css +6 -0
  53. package/front_end/panels/application/ApplicationPanelSidebar.ts +39 -0
  54. package/front_end/panels/application/ApplicationPanelTreeElement.ts +39 -0
  55. package/front_end/panels/application/CookieItemsView.ts +2 -2
  56. package/front_end/panels/application/components/AdsView.ts +219 -0
  57. package/front_end/panels/application/components/adsView.css +54 -0
  58. package/front_end/panels/application/components/components.ts +2 -0
  59. package/front_end/panels/application/resourcesSidebar.css +11 -0
  60. package/front_end/panels/console/SymbolizedErrorWidget.ts +79 -25
  61. package/front_end/panels/network/NetworkLogView.ts +5 -1
  62. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -0
  63. package/front_end/panels/sources/SourcesPanel.ts +2 -1
  64. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +5 -4
  65. package/front_end/third_party/chromium/README.chromium +1 -1
  66. package/front_end/third_party/lighthouse/README.chromium +2 -2
  67. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1607 -5733
  68. package/front_end/third_party/lighthouse/locales/ar-XB.json +290 -65
  69. package/front_end/third_party/lighthouse/locales/ar.json +290 -65
  70. package/front_end/third_party/lighthouse/locales/bg.json +290 -65
  71. package/front_end/third_party/lighthouse/locales/ca.json +295 -70
  72. package/front_end/third_party/lighthouse/locales/cs.json +290 -65
  73. package/front_end/third_party/lighthouse/locales/da.json +294 -69
  74. package/front_end/third_party/lighthouse/locales/de.json +295 -70
  75. package/front_end/third_party/lighthouse/locales/el.json +290 -65
  76. package/front_end/third_party/lighthouse/locales/en-GB.json +290 -65
  77. package/front_end/third_party/lighthouse/locales/en-US.json +79 -67
  78. package/front_end/third_party/lighthouse/locales/en-XA.json +253 -64
  79. package/front_end/third_party/lighthouse/locales/en-XL.json +79 -67
  80. package/front_end/third_party/lighthouse/locales/es-419.json +290 -65
  81. package/front_end/third_party/lighthouse/locales/es.json +298 -73
  82. package/front_end/third_party/lighthouse/locales/fi.json +290 -65
  83. package/front_end/third_party/lighthouse/locales/fil.json +290 -65
  84. package/front_end/third_party/lighthouse/locales/fr.json +294 -69
  85. package/front_end/third_party/lighthouse/locales/he.json +293 -68
  86. package/front_end/third_party/lighthouse/locales/hi.json +291 -66
  87. package/front_end/third_party/lighthouse/locales/hr.json +290 -65
  88. package/front_end/third_party/lighthouse/locales/hu.json +290 -65
  89. package/front_end/third_party/lighthouse/locales/id.json +290 -65
  90. package/front_end/third_party/lighthouse/locales/it.json +294 -69
  91. package/front_end/third_party/lighthouse/locales/ja.json +290 -65
  92. package/front_end/third_party/lighthouse/locales/ko.json +290 -65
  93. package/front_end/third_party/lighthouse/locales/lt.json +290 -65
  94. package/front_end/third_party/lighthouse/locales/lv.json +290 -65
  95. package/front_end/third_party/lighthouse/locales/nl.json +290 -65
  96. package/front_end/third_party/lighthouse/locales/no.json +290 -65
  97. package/front_end/third_party/lighthouse/locales/pl.json +290 -65
  98. package/front_end/third_party/lighthouse/locales/pt-PT.json +291 -66
  99. package/front_end/third_party/lighthouse/locales/pt.json +290 -65
  100. package/front_end/third_party/lighthouse/locales/ro.json +290 -65
  101. package/front_end/third_party/lighthouse/locales/ru.json +301 -76
  102. package/front_end/third_party/lighthouse/locales/sk.json +291 -66
  103. package/front_end/third_party/lighthouse/locales/sl.json +290 -65
  104. package/front_end/third_party/lighthouse/locales/sr-Latn.json +290 -65
  105. package/front_end/third_party/lighthouse/locales/sr.json +290 -65
  106. package/front_end/third_party/lighthouse/locales/sv.json +297 -72
  107. package/front_end/third_party/lighthouse/locales/ta.json +291 -66
  108. package/front_end/third_party/lighthouse/locales/te.json +293 -68
  109. package/front_end/third_party/lighthouse/locales/th.json +291 -66
  110. package/front_end/third_party/lighthouse/locales/tr.json +290 -65
  111. package/front_end/third_party/lighthouse/locales/uk.json +290 -65
  112. package/front_end/third_party/lighthouse/locales/vi.json +291 -66
  113. package/front_end/third_party/lighthouse/locales/zh-HK.json +292 -67
  114. package/front_end/third_party/lighthouse/locales/zh-TW.json +291 -66
  115. package/front_end/third_party/lighthouse/locales/zh.json +291 -66
  116. package/front_end/third_party/lighthouse/report/bundle.d.ts +6 -6
  117. package/front_end/third_party/lighthouse/report/bundle.js +4 -7
  118. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  119. package/front_end/ui/legacy/StackedPane.ts +229 -0
  120. package/front_end/ui/legacy/ViewManager.ts +59 -169
  121. package/front_end/ui/legacy/Widget.ts +32 -8
  122. package/front_end/ui/legacy/legacy.ts +3 -1
  123. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  124. package/mcp/mcp.ts +1 -0
  125. package/package.json +1 -1
@@ -6,6 +6,7 @@ import * as Common from '../../../core/common/common.js';
6
6
  import * as Host from '../../../core/host/host.js';
7
7
  import * as i18n from '../../../core/i18n/i18n.js';
8
8
  import * as Root from '../../../core/root/root.js';
9
+ import type {NetworkRequest} from '../../../core/sdk/NetworkRequest.js';
9
10
  import type * as SDK from '../../../core/sdk/sdk.js';
10
11
  import type * as LHModel from '../../lighthouse/lighthouse.js';
11
12
  import * as Logs from '../../logs/logs.js';
@@ -15,6 +16,7 @@ import * as Workspace from '../../workspace/workspace.js';
15
16
  import {isOpaqueOrigin} from '../AiOrigins.js';
16
17
  import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
17
18
  import {debugLog} from '../debug.js';
19
+ import {StorageItem} from '../StorageItem.js';
18
20
 
19
21
  import {AccessibilityContext} from './AccessibilityAgent.js';
20
22
  import {
@@ -25,8 +27,9 @@ import {
25
27
  type RequestOptions,
26
28
  } from './AiAgent.js';
27
29
  import {FileContext} from './FileAgent.js';
28
- import {RequestContext} from './NetworkAgent.js';
30
+ import {getRequestContextOrigin, RequestContext} from './NetworkAgent.js';
29
31
  import {PerformanceTraceContext} from './PerformanceAgent.js';
32
+ import {StorageContext} from './StorageAgent.js';
30
33
 
31
34
  const lockedString = i18n.i18n.lockedString;
32
35
  /**
@@ -41,12 +44,12 @@ Your role is to understand the user's query, identify the appropriate specialize
41
44
 
42
45
  # Workflow
43
46
  1. **Analyze**: Understand the user's intent and what they are trying to achieve.
44
- 2. **Classify**: Determine which specialized agent is best suited for the task (e.g., StylingAgent for CSS/styling issues, NetworkAgent for network requests, FileAgent for source files, PerformanceAgent for performance details, AccessibilityAgent for accessibility reports, or StorageAgent for storage issues).
45
- 3. **Gather Context**: Identify what information the specialized agent will need. Proactively use your tools to find and select this context (e.g., finding the relevant DOM node, network request, file, or performance trace). Always try to select a single specific context before answering the question.
47
+ 2. **Classify**: Determine which specialized agent is best suited for the task (e.g., StylingAgent for CSS/styling issues, NetworkAgent for network requests, FileAgent for source files, PerformanceAgent for performance details, AccessibilityAgent for accessibility reports, or StorageAgent for analyzing and explaining storage but not editing).
48
+ 3. **Gather Context**: Identify what information the specialized agent will need. Proactively use your tools to find and select this context (e.g., finding the relevant DOM node, network request, file, performance trace, or storage). Always try to select a single specific context before answering the question.
46
49
  4. **Delegate**: Once context is selected, hand over to the specialized agent. If you are unable to delegate or gather more information, provide a comprehensive guide on how to fix the issue using Chrome DevTools, explaining how and why, or suggest any panel/flow that may help.
47
50
 
48
51
  # Considerations
49
- * Determine what is the domain of the question - styling, network, sources, performance or other part of DevTools.
52
+ * Determine what is the domain of the question - styling, network, sources, performance, storage, or other part of DevTools.
50
53
  * For questions about performance (e.g., general performance issues, page speed, performance metrics like LCP, INP, CLS), use performanceRecordAndReload to record a performance trace.
51
54
  * Proactively try to gather additional data. If a specific piece of data can be selected, select it.
52
55
  * Always try to select a single specific context before answering the question.
@@ -141,8 +144,9 @@ export class ContextSelectionAgent extends AiAgent<never> {
141
144
  }
142
145
 
143
146
  let hasCrossOriginRequest = false;
147
+ const requestsToShow: NetworkRequest[] = [];
144
148
  for (const request of Logs.NetworkLog.NetworkLog.instance().requests()) {
145
- const documentOrigin = Common.ParsedURL.ParsedURL.extractOrigin(request.documentURL);
149
+ const requestOrigin = getRequestContextOrigin(request);
146
150
  /**
147
151
  * NOTE: this origin check does not ensure that all the requests are
148
152
  * from the same origin as the target page. Instead, it ensures that
@@ -151,7 +155,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
151
155
  * during the loading of the target page, and do not leak URLs from
152
156
  * other pages.
153
157
  */
154
- if (origin && documentOrigin !== origin) {
158
+ if (origin && requestOrigin !== origin) {
155
159
  hasCrossOriginRequest = true;
156
160
  continue;
157
161
  }
@@ -163,6 +167,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
163
167
  duration: i18n.TimeUtilities.secondsToString(request.duration),
164
168
  transferSize: i18n.ByteUtilities.formatBytesToKb(request.transferSize),
165
169
  });
170
+ requestsToShow.push(request);
166
171
  }
167
172
 
168
173
  if (requests.length === 0) {
@@ -175,6 +180,12 @@ export class ContextSelectionAgent extends AiAgent<never> {
175
180
 
176
181
  return {
177
182
  result: requests,
183
+ widgets: [{
184
+ name: 'NETWORK_REQUESTS_LIST',
185
+ data: {
186
+ requests: requestsToShow,
187
+ },
188
+ }],
178
189
  };
179
190
  },
180
191
  });
@@ -219,8 +230,8 @@ export class ContextSelectionAgent extends AiAgent<never> {
219
230
  return false;
220
231
  }
221
232
 
222
- const documentOrigin = Common.ParsedURL.ParsedURL.extractOrigin(req.documentURL);
223
- return !origin || documentOrigin === origin;
233
+ const requestOrigin = getRequestContextOrigin(req);
234
+ return !origin || requestOrigin === origin;
224
235
  });
225
236
 
226
237
  if (request) {
@@ -478,6 +489,45 @@ export class ContextSelectionAgent extends AiAgent<never> {
478
489
  };
479
490
  },
480
491
  });
492
+
493
+ if (Root.Runtime.hostConfig.devToolsAiAssistanceStorageAgent?.enabled) {
494
+ this.declareFunction<Record<string, never>>('analyzeStorage', {
495
+ description:
496
+ 'Selects the page storage. Use this when asked about browser storage (localStorage, sessionStorage, cookies) and issues related to these.',
497
+ parameters: {
498
+ type: Host.AidaClient.ParametersTypes.OBJECT,
499
+ description: '',
500
+ nullable: true,
501
+ required: [],
502
+ properties: {},
503
+ },
504
+ displayInfoFromArgs: () => {
505
+ return {
506
+ title: lockedString('Prepare storage analysis'),
507
+ action: 'analyzeStorage()',
508
+ };
509
+ },
510
+ handler: async () => {
511
+ const allowedOriginResult = this.#allowedOrigin();
512
+ if ('blocked' in allowedOriginResult) {
513
+ return {
514
+ error: 'Cross-origin access blocked due to navigation. Please start a new chat.',
515
+ };
516
+ }
517
+ const origin = allowedOriginResult.origin;
518
+ if (!origin) {
519
+ return {
520
+ error: 'Unable to find page storage.',
521
+ };
522
+ }
523
+
524
+ return {
525
+ context: new StorageContext(new StorageItem(origin, origin)),
526
+ description: 'User selected page storage',
527
+ };
528
+ },
529
+ });
530
+ }
481
531
  }
482
532
 
483
533
  async * handleContextDetails(): AsyncGenerator<ContextResponse, void, void> {
@@ -12,9 +12,7 @@ import {debugLog} from '../debug.js';
12
12
  import {EvaluateAction, formatError, SideEffectError} from '../EvaluateAction.js';
13
13
  import {FREESTYLER_WORLD_NAME} from '../injected.js';
14
14
 
15
- import type {
16
- AgentOptions as BaseAgentOptions, FunctionCallHandlerResult, FunctionDeclaration, FunctionHandlerOptions,} from
17
- './AiAgent.js';
15
+ import type {AgentOptions as BaseAgentOptions, FunctionCallHandlerResult, FunctionHandlerOptions,} from './AiAgent.js';
18
16
 
19
17
  const lockedString = i18n.i18n.lockedString;
20
18
 
@@ -28,95 +26,6 @@ export interface ExecuteJsAgentOptions extends BaseAgentOptions {
28
26
  execJs?: typeof executeJsCode;
29
27
  }
30
28
 
31
- export function executeJavaScriptFunction(executor: JavascriptExecutor): FunctionDeclaration<
32
- {
33
- title: string,
34
- explanation: string,
35
- code: string,
36
- },
37
- unknown> {
38
- return {
39
- description:
40
- 'This function allows you to run JavaScript code on the inspected page to access the element styles and page content.\nCall this function to gather additional information or modify the page state. Call this function enough times to investigate the user request.',
41
- parameters: {
42
- type: Host.AidaClient.ParametersTypes.OBJECT,
43
- description: '',
44
- nullable: false,
45
- properties: {
46
- code: {
47
- type: Host.AidaClient.ParametersTypes.STRING,
48
- description:
49
- `JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.
50
-
51
- # Instructions
52
-
53
- * To return data, define a top-level \`data\` variable and populate it with data you want to get. Only JSON-serializable objects can be assigned to \`data\`.
54
- * If you modify styles on an element, ALWAYS call the pre-defined global \`async setElementStyles(el: Element, styles: object)\` function. This function is an internal mechanism for you and should never be presented as a command/advice to the user.
55
- * **CRITICAL** Only get styles that might be relevant to the user request.
56
- * **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.
57
- * **CRITICAL** Consider that \`data\` variable from the previous function calls are not available in a new function call.
58
-
59
- For example, the code to change element styles:
60
-
61
- \`\`\`
62
- await setElementStyles($0, {
63
- color: 'blue',
64
- });
65
- \`\`\`
66
-
67
- For example, the code to get overlapping elements:
68
-
69
- \`\`\`
70
- const data = {
71
- overlappingElements: Array.from(document.querySelectorAll('*'))
72
- .filter(el => {
73
- const rect = el.getBoundingClientRect();
74
- const popupRect = $0.getBoundingClientRect();
75
- return (
76
- el !== $0 &&
77
- rect.left < popupRect.right &&
78
- rect.right > popupRect.left &&
79
- rect.top < popupRect.bottom &&
80
- rect.bottom > popupRect.top
81
- );
82
- })
83
- .map(el => ({
84
- tagName: el.tagName,
85
- id: el.id,
86
- className: el.className,
87
- zIndex: window.getComputedStyle(el)['z-index']
88
- }))
89
- };
90
- \`\`\`
91
- `,
92
- },
93
- explanation: {
94
- type: Host.AidaClient.ParametersTypes.STRING,
95
- description: 'Explain why you want to run this code',
96
- },
97
- title: {
98
- type: Host.AidaClient.ParametersTypes.STRING,
99
- description: 'Provide a summary of what the code does. For example, "Checking related element styles".',
100
- },
101
- },
102
- required: ['code', 'explanation', 'title']
103
- },
104
- displayInfoFromArgs: params => {
105
- return {
106
- title: params.title,
107
- thought: params.explanation,
108
- action: params.code,
109
- };
110
- },
111
- handler: async (
112
- params,
113
- options,
114
- ) => {
115
- return await executor.executeAction(params.code, options);
116
- },
117
- };
118
- }
119
-
120
29
  export async function executeJsCode(
121
30
  functionDeclaration: string,
122
31
  {throwOnSideEffect, contextNode}: {throwOnSideEffect: boolean, contextNode: SDK.DOMModel.DOMNode|null}):
@@ -2,11 +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';
5
6
  import * as Host from '../../../core/host/host.js';
6
7
  import * as i18n from '../../../core/i18n/i18n.js';
8
+ import type * as Platform from '../../../core/platform/platform.js';
7
9
  import * as Root from '../../../core/root/root.js';
8
10
  import type * as SDK from '../../../core/sdk/sdk.js';
9
11
  import type * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
12
+ import {extractContextOrigin} from '../AiOrigins.js';
10
13
  import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
11
14
 
12
15
  import {
@@ -98,6 +101,24 @@ const UIStringsNotTranslate = {
98
101
 
99
102
  const lockedString = i18n.i18n.lockedString;
100
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
+
101
122
  export class RequestContext extends ConversationContext<SDK.NetworkRequest.NetworkRequest> {
102
123
  #request: SDK.NetworkRequest.NetworkRequest;
103
124
  #calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
@@ -119,6 +140,10 @@ export class RequestContext extends ConversationContext<SDK.NetworkRequest.Netwo
119
140
  return this.#request.documentURL;
120
141
  }
121
142
 
143
+ override getOrigin(): string {
144
+ return getRequestContextOrigin(this.#request);
145
+ }
146
+
122
147
  override getItem(): SDK.NetworkRequest.NetworkRequest {
123
148
  return this.#request;
124
149
  }
@@ -15,6 +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
19
  import {sanitizeHeaders} from '../data_formatters/NetworkRequestFormatter.js';
19
20
  import {
20
21
  PerformanceInsightFormatter,
@@ -63,12 +64,6 @@ export type MainThreadSectionLabel = 'nav-to-lcp'|'lcp-ttfb'|'lcp-render-delay'|
63
64
  * chrome_preambles.gcl). Sync local changes with the server-side.
64
65
  */
65
66
 
66
- const SECURITY_WARNING = `**CRITICAL CONSTRAINT**: This performance trace was loaded from a file and is static.
67
- You do NOT have access to the live page.
68
- The tool \`getFunctionCode\` is disabled.
69
- Do NOT attempt to use it or instruct the user that you will use it.
70
- Rely only on the trace data and other available tools.`;
71
-
72
67
  const GREEN_DEV_ANNOTATIONS_INSTRUCTIONS = `
73
68
  - CRITICAL: You also have access to functions called addElementAnnotation and addNeworkRequestAnnotation,
74
69
  which should be used to highlight elements and network requests (respectively).
@@ -262,6 +257,27 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
262
257
  }
263
258
  }
264
259
 
260
+ /**
261
+ * Returns the origin for a performance trace in the AI context.
262
+ *
263
+ * To prevent cross-origin prompt injection attacks, imported traces
264
+ * are isolated from live pages. We assign them a virtual origin
265
+ * (`imported-trace://${domain}`) so they do not share the origin of live pages
266
+ * (e.g., `https://${domain}`). This forces a conversation reset when transitioning
267
+ * between imported trace data and live pages.
268
+ */
269
+ override getOrigin(): string {
270
+ const parsedTrace = this.#focus.parsedTrace;
271
+ const url = this.getURL();
272
+ const origin = extractContextOrigin(url);
273
+ const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
274
+ if (!isFresh) {
275
+ const parsed = Common.ParsedURL.ParsedURL.fromString(origin as Platform.DevToolsPath.UrlString);
276
+ return `imported-trace://${parsed ? parsed.domain() : origin}`;
277
+ }
278
+ return origin;
279
+ }
280
+
265
281
  override getItem(): AgentFocus {
266
282
  return this.#focus;
267
283
  }
@@ -710,18 +726,14 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
710
726
  }
711
727
  }
712
728
 
713
- const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(focus.parsedTrace);
714
-
715
729
  if (!selected.length) {
716
730
  this.#additionalSelectionsForDisclosure = [];
717
- const finalQuery = query;
718
- return isFresh ? finalQuery : `${SECURITY_WARNING}\n\n${finalQuery}`;
731
+ return query;
719
732
  }
720
733
 
721
734
  selected.push(`# User query\n\n${query}`);
722
735
  this.#additionalSelectionsForDisclosure = [...selected];
723
- const finalQuery = selected.join('');
724
- return isFresh ? finalQuery : `${SECURITY_WARNING}\n\n${finalQuery}`;
736
+ return selected.join('');
725
737
  }
726
738
 
727
739
  override async * run(initialQuery: string, options: {
@@ -1340,84 +1352,87 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1340
1352
  });
1341
1353
  }
1342
1354
 
1343
- if (isFresh) {
1344
- this.declareFunction<{scriptUrl: UrlString, line: number, column: number}, {result: string}>('getFunctionCode', {
1345
- description:
1346
- 'Returns the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.',
1347
- parameters: {
1348
- type: Host.AidaClient.ParametersTypes.OBJECT,
1349
- description: '',
1350
- nullable: false,
1351
- properties: {
1352
- scriptUrl: {
1353
- type: Host.AidaClient.ParametersTypes.STRING,
1354
- description: 'The url of the function.',
1355
- nullable: false,
1356
- },
1357
- line: {
1358
- type: Host.AidaClient.ParametersTypes.INTEGER,
1359
- description: 'The line number where the function is defined.',
1360
- nullable: false,
1361
- },
1362
- column: {
1363
- type: Host.AidaClient.ParametersTypes.INTEGER,
1364
- description: 'The column number where the function is defined.',
1365
- nullable: false,
1366
- },
1355
+ this.declareFunction<{scriptUrl: UrlString, line: number, column: number}, {result: string}>('getFunctionCode', {
1356
+ description:
1357
+ 'Returns the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.',
1358
+ parameters: {
1359
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1360
+ description: '',
1361
+ nullable: false,
1362
+ properties: {
1363
+ scriptUrl: {
1364
+ type: Host.AidaClient.ParametersTypes.STRING,
1365
+ description: 'The url of the function.',
1366
+ nullable: false,
1367
+ },
1368
+ line: {
1369
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1370
+ description: 'The line number where the function is defined.',
1371
+ nullable: false,
1372
+ },
1373
+ column: {
1374
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1375
+ description: 'The column number where the function is defined.',
1376
+ nullable: false,
1367
1377
  },
1368
- required: ['scriptUrl', 'line', 'column']
1369
1378
  },
1370
- displayInfoFromArgs: args => {
1379
+ required: ['scriptUrl', 'line', 'column']
1380
+ },
1381
+ displayInfoFromArgs: args => {
1382
+ return {
1383
+ title: lockedString('Looking up function code'),
1384
+ action: `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`
1385
+ };
1386
+ },
1387
+ handler: async args => {
1388
+ debugLog('Function call: getFunctionCode');
1389
+ if (!isFresh) {
1371
1390
  return {
1372
- title: lockedString('Looking up function code'),
1373
- action: `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`
1391
+ error: 'Cannot use this tool on an imported file.',
1374
1392
  };
1375
- },
1376
- handler: async args => {
1377
- debugLog('Function call: getFunctionCode');
1393
+ }
1378
1394
 
1379
- if (args.line === undefined) {
1380
- return {error: 'Missing arg: line'};
1381
- }
1395
+ if (args.line === undefined) {
1396
+ return {error: 'Missing arg: line'};
1397
+ }
1382
1398
 
1383
- if (args.column === undefined) {
1384
- return {error: 'Missing arg: column'};
1385
- }
1399
+ if (args.column === undefined) {
1400
+ return {error: 'Missing arg: column'};
1401
+ }
1386
1402
 
1387
- if (!this.#formatter) {
1388
- throw new Error('missing formatter');
1389
- }
1403
+ if (!this.#formatter) {
1404
+ throw new Error('missing formatter');
1405
+ }
1390
1406
 
1391
- const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1392
- if (!target) {
1393
- throw new Error('missing target');
1394
- }
1407
+ const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1408
+ if (!target) {
1409
+ throw new Error('missing target');
1410
+ }
1395
1411
 
1396
- const url = args.scriptUrl as Platform.DevToolsPath.UrlString;
1397
- const code = await this.#formatter.resolveFunctionCodeAtLocation(url, args.line, args.column);
1398
- if (!code) {
1399
- return {error: 'Could not find code'};
1400
- }
1412
+ const url = args.scriptUrl as Platform.DevToolsPath.UrlString;
1413
+ const code = await this.#formatter.resolveFunctionCodeAtLocation(url, args.line, args.column);
1414
+ if (!code) {
1415
+ return {error: 'Could not find code'};
1416
+ }
1401
1417
 
1402
- const result = this.#formatter.formatFunctionCode(code);
1418
+ const result = this.#formatter.formatFunctionCode(code);
1403
1419
 
1404
- const key = `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`;
1405
- this.#cacheFunctionResult(focus, key, result);
1406
- return {
1407
- result: {result},
1408
- widgets: [{
1409
- name: 'SOURCE_CODE',
1410
- data: {
1411
- url: args.scriptUrl,
1412
- line: args.line,
1413
- column: args.column,
1414
- code: code.code,
1415
- },
1416
- }],
1417
- };
1418
- },
1419
- });
1420
- }
1420
+ const key = `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`;
1421
+ this.#cacheFunctionResult(focus, key, result);
1422
+ return {
1423
+ result: {result},
1424
+ widgets: [{
1425
+ name: 'SOURCE_CODE',
1426
+ data: {
1427
+ url: args.scriptUrl,
1428
+ line: args.line,
1429
+ column: args.column,
1430
+ code: code.code,
1431
+ },
1432
+ }],
1433
+ };
1434
+ },
1435
+ });
1421
1436
 
1422
1437
  const isTraceApp = Root.Runtime.Runtime.isTraceApp();
1423
1438