chrome-devtools-frontend 1.0.1592129 → 1.0.1593518

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/front_end/Images/src/tab-move.svg +1 -0
  2. package/front_end/application_tokens.css +4 -4
  3. package/front_end/core/host/UserMetrics.ts +2 -1
  4. package/front_end/core/root/ExperimentNames.ts +1 -0
  5. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  6. package/front_end/generated/InspectorBackendCommands.ts +3 -1
  7. package/front_end/generated/SupportedCSSProperties.js +2 -2
  8. package/front_end/generated/protocol-mapping.d.ts +13 -0
  9. package/front_end/generated/protocol-proxy-api.d.ts +12 -0
  10. package/front_end/generated/protocol.ts +75 -0
  11. package/front_end/models/ai_assistance/agents/AiAgent.ts +24 -1
  12. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +320 -26
  13. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgentOverlay.ts +87 -0
  14. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +8 -8
  15. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +79 -48
  16. package/front_end/models/ai_assistance/agents/StylingAgent.ts +16 -2
  17. package/front_end/models/computed_style/ComputedStyleModel.ts +40 -6
  18. package/front_end/models/javascript_metadata/NativeFunctions.js +6 -6
  19. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +5 -3
  20. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +39 -7
  21. package/front_end/panels/ai_assistance/README.md +61 -0
  22. package/front_end/panels/ai_assistance/components/ChatMessage.ts +141 -27
  23. package/front_end/panels/ai_assistance/components/ChatView.ts +5 -1
  24. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +55 -1
  25. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +19 -7
  26. package/front_end/panels/ai_assistance/components/chatMessage.css +30 -0
  27. package/front_end/panels/ai_assistance/components/walkthroughView.css +12 -7
  28. package/front_end/panels/animation/AnimationGroupPreviewUI.ts +1 -1
  29. package/front_end/panels/application/CookieItemsView.ts +194 -134
  30. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +1 -1
  31. package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +1 -0
  32. package/front_end/panels/application/StorageItemsToolbar.ts +25 -2
  33. package/front_end/panels/application/components/BackForwardCacheView.ts +4 -2
  34. package/front_end/panels/application/cookieItemsView.css +28 -26
  35. package/front_end/panels/autofill/AutofillView.ts +1 -1
  36. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +161 -154
  37. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +1 -0
  38. package/front_end/panels/browser_debugger/domBreakpointsSidebarPane.css +58 -36
  39. package/front_end/panels/console/ConsoleViewMessage.ts +2 -1
  40. package/front_end/panels/console/consoleView.css +7 -2
  41. package/front_end/panels/elements/ComputedStyleWidget.ts +16 -26
  42. package/front_end/panels/elements/ElementsPanel.ts +26 -3
  43. package/front_end/panels/elements/ElementsTreeElement.ts +1 -0
  44. package/front_end/panels/elements/LayoutPane.ts +8 -7
  45. package/front_end/panels/elements/StandaloneStylesContainer.ts +254 -0
  46. package/front_end/panels/elements/StylePropertyTreeElement.ts +33 -0
  47. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +148 -1
  48. package/front_end/panels/elements/components/ComputedStyleTrace.ts +4 -0
  49. package/front_end/panels/elements/components/ElementsBreadcrumbs.ts +1 -1
  50. package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -1
  51. package/front_end/panels/elements/components/computedStyleProperty.css +1 -1
  52. package/front_end/panels/elements/elements-meta.ts +3 -5
  53. package/front_end/panels/elements/elements.ts +2 -0
  54. package/front_end/panels/elements/stylePropertiesTreeOutline.css +6 -0
  55. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -1
  56. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +1 -1
  57. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +1 -1
  58. package/front_end/panels/media/PlayerListView.ts +1 -1
  59. package/front_end/panels/network/NetworkLogViewColumns.ts +2 -1
  60. package/front_end/panels/network/components/RequestHeaderSection.ts +1 -1
  61. package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
  62. package/front_end/panels/recorder/components/RecordingListView.ts +1 -1
  63. package/front_end/panels/recorder/components/StepEditor.ts +3 -3
  64. package/front_end/panels/settings/KeybindsSettingsTab.ts +2 -1
  65. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  66. package/front_end/panels/timeline/components/BreadcrumbsUI.ts +1 -1
  67. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -1
  68. package/front_end/panels/timeline/components/metricCard.css +0 -4
  69. package/front_end/third_party/chromium/README.chromium +1 -1
  70. package/front_end/third_party/puppeteer/README.chromium +2 -2
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.d.ts.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.js +1 -0
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.js.map +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js.map +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  83. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  84. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  85. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +6 -6
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.d.ts.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.js +1 -0
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.js.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
  99. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  100. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  101. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  104. package/front_end/third_party/puppeteer/package/package.json +4 -4
  105. package/front_end/third_party/puppeteer/package/src/bidi/core/Navigation.ts +1 -0
  106. package/front_end/third_party/puppeteer/package/src/cdp/BrowserContext.ts +1 -1
  107. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +1 -1
  108. package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
  109. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  110. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  111. package/front_end/ui/components/suggestion_input/SuggestionInput.ts +7 -12
  112. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +13 -2
  113. package/front_end/ui/components/tree_outline/TreeOutline.ts +6 -2
  114. package/front_end/ui/components/tree_outline/treeOutline.css +5 -0
  115. package/front_end/ui/legacy/ListControl.ts +5 -3
  116. package/front_end/ui/legacy/ListWidget.ts +1 -1
  117. package/front_end/ui/legacy/SoftContextMenu.ts +2 -1
  118. package/front_end/ui/legacy/Treeoutline.ts +1 -0
  119. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +44 -24
  120. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +4 -2
  121. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -1
  122. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +31 -0
  123. package/front_end/ui/visual_logging/Debugging.ts +4 -0
  124. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  125. package/package.json +1 -1
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type * as Common from '../../../core/common/common.js';
6
6
  import * as Host from '../../../core/host/host.js';
7
+ import * as i18n from '../../../core/i18n/i18n.js';
7
8
  import type * as Platform from '../../../core/platform/platform.js';
8
9
  import * as SDK from '../../../core/sdk/sdk.js';
9
10
  import * as Bindings from '../../bindings/bindings.js';
@@ -20,9 +21,18 @@ import {
20
21
  type ContextResponse,
21
22
  ConversationContext,
22
23
  type FunctionCallHandlerResult,
24
+ type FunctionHandlerOptions,
25
+ type MultimodalInput,
23
26
  type RequestOptions,
27
+ type ResponseData,
24
28
  ResponseType,
25
29
  } from './AiAgent.js';
30
+ import {
31
+ injectOverlay,
32
+ removeOverlay,
33
+ } from './BreakpointDebuggerAgentOverlay.js';
34
+
35
+ const lockedString = i18n.i18n.lockedString;
26
36
 
27
37
  // This is a temporary agent for a GreenDev prototype.
28
38
  // The preamble is not on the server and you should not build on top of this.
@@ -39,20 +49,24 @@ You have two modes of operation that you can switch between and control:
39
49
  **Workflow**:
40
50
  1. **Hypothesize**: Read the code ('getFunctionSource', 'getPreviousLines', 'getNextLines') to understand the logic.
41
51
  2. **Set Trap**: Identify the critical line where state corruption likely occurred or lines that can lead you to that place. Use 'setBreakpoint' on that line.
42
- 3. **Wait**: Call 'waitForBreakpoint'. This will suspend your execution until the user triggers the breakpoint. You CANNOT proceed until this tool returns.
52
+ 3. **Wait**: Call 'waitForUserActionToTriggerBreakpoint'. This will suspend your execution until the user triggers the breakpoint. You CANNOT proceed until this tool returns.
43
53
  4. **Inspect**: Using 'getExecutionLocation' check exactly where you are paused.
44
54
  5. **Analyze**: When paused (Runtime Mode), use 'getScopeVariables' and 'getCallStack' to verify your hypothesis. Check variables in multiple scopes and look up the call stack to see where bad data came from.
45
55
  6. **Step**: Use 'stepInto' to investigate function calls on the current line. Use 'stepOut' to return to the caller. Use 'stepOver' to move to the next line.
46
56
  7. **Trace Back**: If the current function isn't the root cause, use 'getCallStack' to find the caller, and repeat the analysis there.
47
57
  8. **Root Cause**: Explain exactly how the runtime state contradicts the expected logic and point to the specific line of code that is the root cause.
58
+ 9. **Apply Fix**: Use the 'testFixInConsole' tool to overwrite the problematic code in the current session.
59
+ 10. **Verify**: The fix is applied but NOT verified. You MUST run the code again to verify the fix worked.
60
+ 11. **Finish**: If the fix worked, you may output the solution and finish the execution.
48
61
 
49
62
  **Rules**:
50
- - **NEVER FINISH** execution until you have found the root cause or answer.
51
- - **ACTION OVER TALK**: If you need the user to trigger a breakpoint, do NOT just ask them in text. You **MUST** call 'waitForBreakpoint'. This tool will block and wait for the user to act.
52
- - **STATIC MODE**: If you are in STATIC MODE and need to see variables: 1. 'setBreakpoint', 2. 'waitForBreakpoint'. **DO NOT STOP** to ask the user. Investigate code and set breakpoints to find the root cause.
53
- - **ALREADY PAUSED?**: If 'setBreakpoint' warns you that you are already paused, **DO NOT** call 'waitForBreakpoint'. Start inspecting immediately. You can set more breakpoints while paused, but to call 'waitForBreakpoint' again you MUST be in static state.
63
+ - **NEVER FINISH** execution until you have found the root cause and verified the fix.
64
+ - **ACTION OVER TALK**: If you need the user to trigger a breakpoint, do NOT just ask them in text. You **MUST** call 'waitForUserActionToTriggerBreakpoint'. This tool will block and wait for the user to act.
65
+ - **STATIC MODE**: If you are in STATIC MODE and need to see variables: 1. 'setBreakpoint', 2. 'waitForUserActionToTriggerBreakpoint'. **DO NOT STOP** to ask the user. Investigate code and set breakpoints to find the root cause.
66
+ - **ALREADY PAUSED?**: If 'setBreakpoint' warns you that you are already paused, **DO NOT** call 'waitForUserActionToTriggerBreakpoint'. Start inspecting immediately. You can set more breakpoints while paused, but to call 'waitForUserActionToTriggerBreakpoint' again you MUST be in static state.
54
67
  - **USE TOOLS EXCESSIVELY**: checking one thing is often not enough. Check everything you can thinks of.
55
- - **CHECK LOCATION**: If you are not sure where you are, call 'getExecutionLocation' after 'waitForBreakpoint' or any step command to confirm where you are.
68
+ - **CHECK LOCATION**: If you are not sure where you are, call 'getExecutionLocation' after 'waitForUserActionToTriggerBreakpoint' or any step command to confirm where you are.
69
+ - **INITIAL CONTEXT**: The breakpoint provided in the context is ALREADY SET. Do NOT set it again. Start by setting additional breakpoints if needed, or, if no additional breakpoints within the code you see make sense, call 'waitForUserActionToTriggerBreakpoint'.
56
70
 
57
71
  **Execution Control when you are currently on a breakpoint**:
58
72
  - **stepInto**: ESSENTIAL for entering function calls on the current line. Use this heavily when you suspect the issue is inside a called function.
@@ -60,6 +74,8 @@ You have two modes of operation that you can switch between and control:
60
74
  - **stepOut**: Return to the caller. If you are currently on a breakpoint, 'stepOut' will move you to the caller and pause again. **It often makes sense to 'stepOut' after you have investigated a function with 'stepInto' and verified it is correct.**
61
75
  - **stepInto, stepOver, stepOut**: After any step command, always call 'getScopeVariables' to see how the state evolved.
62
76
  - **listBreakpoints**: Use this to see all active breakpoints. Do not try to set a breakpoint that is already active.
77
+ - **removeBreakpoint / removeAllBreakpoints**: Use this to remove breakpoints. This is especially useful when you want to speed up verifying a fix.
78
+ - **CLEANUP AFTER FIX**: After a fix is suggested and worked, you MUST remove all breakpoints and call 'resume' to resume the execution of the page.
63
79
  `;
64
80
 
65
81
  export class BreakpointContext extends ConversationContext<Workspace.UISourceCode.UILocation> {
@@ -108,6 +124,13 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
108
124
  },
109
125
  required: ['url', 'lineNumber'],
110
126
  },
127
+ displayInfoFromArgs: (args: {url: string, lineNumber: number}) => {
128
+ const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(
129
+ args.url as Platform.DevToolsPath.UrlString);
130
+ return {
131
+ title: `Reading function source for ${uiSourceCode?.displayName()}:${args.lineNumber}`,
132
+ };
133
+ },
111
134
  handler: async (args: {url: string, lineNumber: number}) => {
112
135
  const result = await this.#getFunctionSource(args);
113
136
  debugLog('getFunctionSource for ', JSON.stringify(args), '->', JSON.stringify(result));
@@ -137,6 +160,13 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
137
160
  },
138
161
  required: ['url', 'lineNumber', 'direction'],
139
162
  },
163
+ displayInfoFromArgs: (args: {url: string, lineNumber: number, direction: 'before'|'after'}) => {
164
+ const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(
165
+ args.url as Platform.DevToolsPath.UrlString);
166
+ return {
167
+ title: `Reading code ${args.direction} ${uiSourceCode?.displayName()}:${args.lineNumber}`,
168
+ };
169
+ },
140
170
  handler: async (args: {url: string, lineNumber: number, direction: 'before'|'after'}) => {
141
171
  const result = await this.#getCodeLines(args);
142
172
  debugLog('getCodeLines result', JSON.stringify(result));
@@ -151,6 +181,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
151
181
  properties: {},
152
182
  required: [],
153
183
  },
184
+ displayInfoFromArgs: () => {
185
+ return {
186
+ title: 'Reading call stack',
187
+ };
188
+ },
154
189
  handler: async () => {
155
190
  const result = await this.#getCallStack();
156
191
  debugLog('getCallStack result', JSON.stringify(result));
@@ -165,6 +200,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
165
200
  properties: {},
166
201
  required: [],
167
202
  },
203
+ displayInfoFromArgs: () => {
204
+ return {
205
+ title: 'Reading scope variables',
206
+ };
207
+ },
168
208
  handler: async () => {
169
209
  const result = await this.#getScopeVariables();
170
210
  debugLog('getScopeVariables result', JSON.stringify(result));
@@ -179,6 +219,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
179
219
  properties: {},
180
220
  required: [],
181
221
  },
222
+ displayInfoFromArgs: () => {
223
+ return {
224
+ title: 'Listing breakpoints',
225
+ };
226
+ },
182
227
  handler: async () => {
183
228
  const result = await this.#listBreakpoints();
184
229
  debugLog('listBreakpoints result', JSON.stringify(result));
@@ -202,6 +247,13 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
202
247
  },
203
248
  required: ['url', 'lineNumber'],
204
249
  },
250
+ displayInfoFromArgs: (args: {url: string, lineNumber: number}) => {
251
+ const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(
252
+ args.url as Platform.DevToolsPath.UrlString);
253
+ return {
254
+ title: `Setting breakpoint at ${uiSourceCode?.displayName() ?? args.url}:${args.lineNumber}`,
255
+ };
256
+ },
205
257
  handler: async (args: {url: string, lineNumber: number}) => {
206
258
  debugLog('setBreakpoint requested', args);
207
259
  const result = await this.#setBreakpoint(args);
@@ -209,18 +261,80 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
209
261
  return result;
210
262
  },
211
263
  });
264
+ this.declareFunction('removeBreakpoint', {
265
+ description: 'Remove a breakpoint at a specific location.',
266
+ parameters: {
267
+ type: Host.AidaClient.ParametersTypes.OBJECT,
268
+ description: 'Location to remove the breakpoint from',
269
+ properties: {
270
+ url: {
271
+ type: Host.AidaClient.ParametersTypes.STRING,
272
+ description: 'The URL of the file',
273
+ },
274
+ lineNumber: {
275
+ type: Host.AidaClient.ParametersTypes.INTEGER,
276
+ description: 'The 1-based line number to remove the breakpoint from',
277
+ },
278
+ },
279
+ required: ['url', 'lineNumber'],
280
+ },
281
+ displayInfoFromArgs: (args: {url: string, lineNumber: number}) => {
282
+ const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(
283
+ args.url as Platform.DevToolsPath.UrlString);
284
+ return {
285
+ title: `Removing breakpoint at ${uiSourceCode?.displayName() ?? args.url}:${args.lineNumber}`,
286
+ };
287
+ },
288
+ handler: async (args: {url: string, lineNumber: number}) => {
289
+ debugLog('removeBreakpoint requested', args);
290
+ const result = await this.#removeBreakpoint(args);
291
+ debugLog('removeBreakpoint result', JSON.stringify(result));
292
+ return result;
293
+ },
294
+ });
295
+ this.declareFunction('removeAllBreakpoints', {
296
+ description: 'Remove all active breakpoints.',
297
+ parameters: {
298
+ type: Host.AidaClient.ParametersTypes.OBJECT,
299
+ description: 'No parameters required',
300
+ properties: {},
301
+ required: [],
302
+ },
303
+ displayInfoFromArgs: () => {
304
+ return {
305
+ title: 'Removing all breakpoints',
306
+ };
307
+ },
308
+ handler: async () => {
309
+ debugLog('removeAllBreakpoints requested');
310
+ const breakpointManager = Breakpoints.BreakpointManager.BreakpointManager.instance();
311
+ const allBreakpoints = breakpointManager.allBreakpointLocations();
312
+ for (const bp of allBreakpoints) {
313
+ await bp.breakpoint.remove(false);
314
+ }
315
+ return {result: {status: 'All breakpoints removed.'}};
316
+ },
317
+ });
212
318
  this.declareFunction('resume', {
213
- description: 'Resume execution until the next breakpoint is hit.',
319
+ description: 'Resume execution. Always use this after applying a fix to resume the page execution.',
214
320
  parameters: {
215
321
  type: Host.AidaClient.ParametersTypes.OBJECT,
216
322
  description: 'No parameters required',
217
323
  properties: {},
218
324
  required: [],
219
325
  },
326
+ displayInfoFromArgs: () => {
327
+ return {
328
+ title: 'Resuming execution',
329
+ };
330
+ },
220
331
  handler: async () => {
221
- const result = await this.#debuggerAction(model => model.resume());
222
- debugLog('resume result', JSON.stringify(result));
223
- return result;
332
+ const targetManager = SDK.TargetManager.TargetManager.instance();
333
+ const debuggerModel = targetManager.models(SDK.DebuggerModel.DebuggerModel).find(m => m.isPaused());
334
+ if (debuggerModel) {
335
+ debuggerModel.resume();
336
+ }
337
+ return {result: {status: 'Execution resumed.'}};
224
338
  },
225
339
  });
226
340
  this.declareFunction('stepOver', {
@@ -231,6 +345,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
231
345
  properties: {},
232
346
  required: [],
233
347
  },
348
+ displayInfoFromArgs: () => {
349
+ return {
350
+ title: 'Stepping over',
351
+ };
352
+ },
234
353
  handler: async () => {
235
354
  const result = await this.#debuggerAction(model => model.stepOver());
236
355
  debugLog('stepOver result', JSON.stringify(result));
@@ -246,6 +365,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
246
365
  properties: {},
247
366
  required: [],
248
367
  },
368
+ displayInfoFromArgs: () => {
369
+ return {
370
+ title: 'Stepping into',
371
+ };
372
+ },
249
373
  handler: async () => {
250
374
  const result = await this.#debuggerAction(model => model.stepInto());
251
375
  debugLog('stepInto result', JSON.stringify(result));
@@ -261,6 +385,11 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
261
385
  properties: {},
262
386
  required: [],
263
387
  },
388
+ displayInfoFromArgs: () => {
389
+ return {
390
+ title: 'Stepping out',
391
+ };
392
+ },
264
393
  handler: async () => {
265
394
  const result = await this.#debuggerAction(model => model.stepOut());
266
395
  debugLog('stepOut result', JSON.stringify(result));
@@ -298,12 +427,97 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
298
427
  properties: {},
299
428
  required: [],
300
429
  },
430
+ displayInfoFromArgs: () => {
431
+ return {
432
+ title: 'Getting execution location',
433
+ };
434
+ },
301
435
  handler: async () => {
302
436
  const result = await this.#getExecutionLocation();
303
437
  debugLog('getExecutionLocation ', JSON.stringify(result));
304
438
  return result;
305
439
  },
306
440
  });
441
+
442
+ this.declareFunction('testFixInConsole', {
443
+ description:
444
+ 'Tests a JavaScript code snippet in the current execution context to overwrite the problematic code or state. After running this, verify the fix worked.',
445
+ parameters: {
446
+ type: Host.AidaClient.ParametersTypes.OBJECT,
447
+ description: 'Provide the code to evaluate to test the fix',
448
+ properties: {
449
+ code: {
450
+ type: Host.AidaClient.ParametersTypes.STRING,
451
+ description: 'The JavaScript code to evaluate in the console to test the fix.',
452
+ },
453
+ explanation: {
454
+ type: Host.AidaClient.ParametersTypes.STRING,
455
+ description: 'Explanation for why this code fixes the issue.',
456
+ },
457
+ },
458
+ required: ['code', 'explanation'],
459
+ },
460
+ displayInfoFromArgs: (args: {code: string, explanation: string}) => {
461
+ return {
462
+ title: 'Testing a fix in console',
463
+ thought: args.explanation,
464
+ action: args.code,
465
+ };
466
+ },
467
+ handler: async (args: {code: string, explanation: string}, options?: FunctionHandlerOptions) => {
468
+ debugLog('testFixInConsole requested', args);
469
+ if (options?.approved === false) {
470
+ return {error: 'Fix rejected by the user.'};
471
+ }
472
+ if (!options?.approved) {
473
+ return {
474
+ requiresApproval: true,
475
+ description: lockedString('This code may modify page content. Continue?'),
476
+ };
477
+ }
478
+
479
+ const targetManager = SDK.TargetManager.TargetManager.instance();
480
+ const debuggerModel = targetManager.models(SDK.DebuggerModel.DebuggerModel).find(m => m.isPaused());
481
+
482
+ if (!debuggerModel) {
483
+ return {error: 'Execution is not paused.'};
484
+ }
485
+
486
+ const details = debuggerModel.debuggerPausedDetails();
487
+ const callFrame = details?.callFrames[0];
488
+ if (!callFrame) {
489
+ return {error: 'No call frame available.'};
490
+ }
491
+
492
+ const result = await callFrame.evaluate({
493
+ expression: args.code,
494
+ objectGroup: 'console',
495
+ includeCommandLineAPI: true,
496
+ silent: false,
497
+ returnByValue: false,
498
+ generatePreview: true
499
+ });
500
+
501
+ if (!result) {
502
+ return {error: 'Failed to evaluate the fix.'};
503
+ }
504
+
505
+ if ('error' in result) {
506
+ return {error: 'Error applying fix: ' + (result as unknown as {error: string}).error};
507
+ }
508
+
509
+ if (result.exceptionDetails) {
510
+ return {error: 'Fix threw an exception: ' + result.exceptionDetails.text};
511
+ }
512
+
513
+ return {
514
+ result: {
515
+ status:
516
+ 'Code evaluated successfully. Fix applied. PROCEED TO VERIFICATION: Call "resume" and ask the user to "run the code again" to verify.'
517
+ }
518
+ };
519
+ },
520
+ });
307
521
  }
308
522
 
309
523
  async #getFunctionSource(args: {url: string, lineNumber: number}):
@@ -407,7 +621,7 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
407
621
  if (!debuggerModel) {
408
622
  return {
409
623
  error:
410
- 'Execution is not paused. I cannot access runtime variables or the call stack. I am currently in STATIC MODE. I must set a breakpoint and use waitForBreakpoint to enter RUNTIME MODE.'
624
+ 'Execution is not paused. I cannot access runtime variables or the call stack. I am currently in STATIC MODE. I must set a breakpoint and use waitForUserActionToTriggerBreakpoint to enter RUNTIME MODE.'
411
625
  };
412
626
  }
413
627
 
@@ -439,7 +653,7 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
439
653
  if (!debuggerModel) {
440
654
  return {
441
655
  error:
442
- 'Execution is not paused. I cannot access runtime variables or the call stack. I am currently in STATIC MODE. I must set a breakpoint and use waitForBreakpoint to enter RUNTIME MODE.'
656
+ 'Execution is not paused. I cannot access runtime variables or the call stack. I am currently in STATIC MODE. I must set a breakpoint and use waitForUserActionToTriggerBreakpoint to enter RUNTIME MODE.'
443
657
  };
444
658
  }
445
659
 
@@ -566,7 +780,7 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
566
780
  if (callFrame) {
567
781
  const pausedLoc = `${callFrame.script.contentURL()}:${callFrame.location().lineNumber + 1}`;
568
782
  warning = ` WARNING: You are already PAUSED at ${
569
- pausedLoc}. \n1. If this is where you want to be, call 'getExecutionLocation' and inspect variables. \n2. If you want to wait for the NEW breakpoint, you MUST call 'waitForBreakpoint' (which will resume execution).`;
783
+ pausedLoc}. \n1. If this is where you want to be, call 'getExecutionLocation' and inspect variables. \n2. If you want to wait for the NEW breakpoint, you MUST call 'waitForUserActionToTriggerBreakpoint' (which will resume execution).`;
570
784
  }
571
785
  }
572
786
 
@@ -575,8 +789,9 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
575
789
  result: {
576
790
  status: `Breakpoint requested at ${args.url}:${args.lineNumber}, but ACTUALLY resolved to line ${
577
791
  actualLineNumber}.${
578
- warning ? '\n' + warning :
579
- ' You must now call waitForBreakpoint and ask the user to trigger the action.'}`
792
+ warning ?
793
+ '\n' + warning :
794
+ ' You must now call waitForUserActionToTriggerBreakpoint and ask the user to trigger the action.'}`
580
795
  }
581
796
  };
582
797
  }
@@ -584,11 +799,33 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
584
799
  return {
585
800
  result: {
586
801
  status: `Breakpoint set at ${args.url}:${args.lineNumber}.${
587
- warning ? '\n' + warning : ' You must now call waitForBreakpoint and ask the user to trigger the action.'}`
802
+ warning ?
803
+ '\n' + warning :
804
+ ' You must now call waitForUserActionToTriggerBreakpoint and ask the user to trigger the action.'}`
588
805
  }
589
806
  };
590
807
  }
591
808
 
809
+ async #removeBreakpoint(args: {url: string, lineNumber: number}):
810
+ Promise<FunctionCallHandlerResult<{status: string}>> {
811
+ const uiSourceCode =
812
+ Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(args.url as Platform.DevToolsPath.UrlString);
813
+ if (!uiSourceCode) {
814
+ return {error: `File not found: ${args.url}`};
815
+ }
816
+
817
+ const breakpointLocations =
818
+ Breakpoints.BreakpointManager.BreakpointManager.instance().breakpointLocationsForUISourceCode(uiSourceCode);
819
+ const breakpointLocation = breakpointLocations.find(bp => bp.uiLocation.lineNumber === args.lineNumber - 1);
820
+
821
+ if (!breakpointLocation) {
822
+ return {result: {status: `Breakpoint not found at ${args.url}:${args.lineNumber}.`}};
823
+ }
824
+
825
+ await breakpointLocation.breakpoint.remove(false);
826
+ return {result: {status: `Breakpoint removed at ${args.url}:${args.lineNumber}.`}};
827
+ }
828
+
592
829
  async #debuggerAction(action: (model: SDK.DebuggerModel.DebuggerModel) => void):
593
830
  Promise<FunctionCallHandlerResult<{status: string}>> {
594
831
  const targetManager = SDK.TargetManager.TargetManager.instance();
@@ -598,8 +835,8 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
598
835
  return {error: 'Execution is not paused. I cannot step or resume in STATIC MODE.'};
599
836
  }
600
837
 
601
- // Only resolve when next pause event is triggered
602
- return await this.#waitForNextPause(() => action(debuggerModel));
838
+ // Only resolve when next pause event is triggered (with a 3 second timeout so the agent doesn't hang)
839
+ return await this.#waitForNextPause(() => action(debuggerModel), 3000);
603
840
  }
604
841
 
605
842
  async #waitForUserActionToTriggerBreakpoint(): Promise<FunctionCallHandlerResult<{status: string}>> {
@@ -610,14 +847,23 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
610
847
  return {error: 'No debugger attached'};
611
848
  }
612
849
 
613
- return await this.#waitForNextPause(() => {
614
- // Resume all paused models before waiting for the next breakpoint
615
- for (const model of debuggerModels) {
616
- if (model.isPaused()) {
617
- model.resume();
850
+ // While waiting for the user to trigger the breakpoint, show an overlay on top of the page.
851
+ // This is to make it clear to the user that they need to trigger the
852
+ // breakpoint for the agent to continue the debugging process.
853
+ void injectOverlay();
854
+
855
+ try {
856
+ return await this.#waitForNextPause(() => {
857
+ // Resume all paused models before waiting for the next breakpoint
858
+ for (const model of debuggerModels) {
859
+ if (model.isPaused()) {
860
+ model.resume();
861
+ }
618
862
  }
619
- }
620
- });
863
+ });
864
+ } finally {
865
+ void removeOverlay();
866
+ }
621
867
  }
622
868
 
623
869
  /**
@@ -626,14 +872,20 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
626
872
  *
627
873
  * @param triggerAction Optional action to execute (e.g. resume, step) that is expected to lead to a pause.
628
874
  */
629
- async #waitForNextPause(triggerAction: () => void = () => {}): Promise<FunctionCallHandlerResult<{status: string}>> {
875
+ async #waitForNextPause(triggerAction: () => void = () => {}, timeoutMs?: number):
876
+ Promise<FunctionCallHandlerResult<{status: string}>> {
630
877
  const targetManager = SDK.TargetManager.TargetManager.instance();
631
878
 
632
879
  return await new Promise(resolve => {
880
+ let timeoutId: ReturnType<typeof setTimeout>;
881
+
633
882
  const listener =
634
883
  async(event: Common.EventTarget.EventTargetEvent<SDK.DebuggerModel.DebuggerModel>): Promise<void> => {
635
884
  targetManager.removeModelListener(
636
885
  SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, listener);
886
+ if (timeoutId) {
887
+ clearTimeout(timeoutId);
888
+ }
637
889
  const model = event.data;
638
890
  const details = model.debuggerPausedDetails();
639
891
  const callFrame = details?.callFrames[0];
@@ -655,6 +907,19 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
655
907
  targetManager.addModelListener(
656
908
  SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, listener);
657
909
 
910
+ if (timeoutMs !== undefined) {
911
+ timeoutId = setTimeout(() => {
912
+ targetManager.removeModelListener(
913
+ SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, listener);
914
+ resolve({
915
+ result: {
916
+ status:
917
+ 'Execution resumed but did not pause again. There is nothing to step into or the execution finished.'
918
+ }
919
+ });
920
+ }, timeoutMs);
921
+ }
922
+
658
923
  // Execute the action that will eventually trigger the pause
659
924
  triggerAction();
660
925
  });
@@ -719,4 +984,33 @@ export class BreakpointDebuggerAgent extends AiAgent<Workspace.UISourceCode.UILo
719
984
  get options(): RequestOptions {
720
985
  return {temperature: 0, modelId: undefined};
721
986
  }
987
+
988
+ override async *
989
+ run(
990
+ initialQuery: string,
991
+ options: {
992
+ selected: ConversationContext<Workspace.UISourceCode.UILocation>|null,
993
+ signal?: AbortSignal,
994
+ },
995
+ multimodalInput?: MultimodalInput,
996
+ ): AsyncGenerator<ResponseData, void, void> {
997
+ try {
998
+ yield* super.run(initialQuery, options, multimodalInput);
999
+ } finally {
1000
+ // When the agent is done, remove all breakpoints and exit paused state.
1001
+ const breakpointManager = Breakpoints.BreakpointManager.BreakpointManager.instance();
1002
+ const allBreakpoints = breakpointManager.allBreakpointLocations();
1003
+ for (const bp of allBreakpoints) {
1004
+ await bp.breakpoint.remove(false);
1005
+ }
1006
+
1007
+ const targetManager = SDK.TargetManager.TargetManager.instance();
1008
+ const debuggerModels = targetManager.models(SDK.DebuggerModel.DebuggerModel);
1009
+ for (const model of debuggerModels) {
1010
+ if (model.isPaused()) {
1011
+ model.resume();
1012
+ }
1013
+ }
1014
+ }
1015
+ }
722
1016
  }
@@ -0,0 +1,87 @@
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
+ /**
6
+ * This file contains the overlay script that is injected into the page when the
7
+ * BreakpointDebuggerAgent is waiting for a user action.
8
+ *
9
+ * This is a temporary solution for the prototype. In the long term, we should
10
+ * use a proper overlay or a different mechanism to communicate with the user,
11
+ * rather than injecting a script into the page. This approach is fine for the
12
+ * prototype but should be replaced before production.
13
+ */
14
+
15
+ import * as SDK from '../../../core/sdk/sdk.js';
16
+
17
+ export async function injectOverlay(): Promise<void> {
18
+ const targetManager = SDK.TargetManager.TargetManager.instance();
19
+ const primaryTarget = targetManager.primaryPageTarget();
20
+
21
+ await primaryTarget?.runtimeAgent().invoke_evaluate({
22
+ expression: WAIT_FOR_USER_ACTION_OVERLAY_SCRIPT,
23
+ });
24
+ }
25
+
26
+ export async function removeOverlay(): Promise<void> {
27
+ const targetManager = SDK.TargetManager.TargetManager.instance();
28
+ const primaryTarget = targetManager.primaryPageTarget();
29
+
30
+ await primaryTarget?.runtimeAgent().invoke_evaluate({
31
+ expression: REMOVE_OVERLAY_SCRIPT,
32
+ });
33
+ }
34
+
35
+ const WAIT_FOR_USER_ACTION_OVERLAY_SCRIPT = `
36
+ (function() {
37
+ const devtoolsOverlayId = 'devtools-waiting-overlay';
38
+ let overlay = document.getElementById(devtoolsOverlayId);
39
+ if (!overlay) {
40
+ overlay = document.createElement('div');
41
+ overlay.id = devtoolsOverlayId;
42
+ overlay.style.position = 'fixed';
43
+ overlay.style.top = '0';
44
+ overlay.style.left = '0';
45
+ overlay.style.width = '100vw';
46
+ overlay.style.height = '100vh';
47
+ overlay.style.pointerEvents = 'none';
48
+ overlay.style.zIndex = '2147483647';
49
+ overlay.style.boxSizing = 'border-box';
50
+ overlay.style.border = '10px solid red';
51
+ overlay.style.animation = 'devtools-fade 1.5s infinite alternate';
52
+ const text = document.createElement('div');
53
+ text.innerText = 'Trigger the breakpoint again';
54
+ text.style.position = 'absolute';
55
+ text.style.top = '10px';
56
+ text.style.left = '50%';
57
+ text.style.transform = 'translateX(-50%)';
58
+ text.style.backgroundColor = 'red';
59
+ text.style.color = 'white';
60
+ text.style.padding = '10px 20px';
61
+ text.style.borderRadius = '5px';
62
+ text.style.fontFamily = 'system-ui, sans-serif';
63
+ text.style.fontSize = '16px';
64
+ text.style.fontWeight = 'bold';
65
+ text.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
66
+ overlay.appendChild(text);
67
+
68
+ const style = document.createElement('style');
69
+ style.id = devtoolsOverlayId + '-style';
70
+ style.innerText = '@keyframes devtools-fade { from { opacity: 0.5; } to { opacity: 1; } }';
71
+ // Head might not exist immediately on a completely blank page, fallback to documentElement
72
+ (document.head || document.documentElement).appendChild(style);
73
+
74
+ document.documentElement.appendChild(overlay);
75
+ }
76
+ })();
77
+ `;
78
+
79
+ const REMOVE_OVERLAY_SCRIPT = `
80
+ (function() {
81
+ const devtoolsOverlayId = 'devtools-waiting-overlay';
82
+ const overlay = document.getElementById(devtoolsOverlayId);
83
+ if (overlay) overlay.remove();
84
+ const style = document.getElementById(devtoolsOverlayId + '-style');
85
+ if (style) style.remove();
86
+ })();
87
+ `;
@@ -48,12 +48,12 @@ Content:
48
48
  "description": "",
49
49
  "nullable": true,
50
50
  "required": [
51
- "url"
51
+ "id"
52
52
  ],
53
53
  "properties": {
54
- "url": {
54
+ "id": {
55
55
  "type": 1,
56
- "description": "The url of the requests",
56
+ "description": "The id of the network request",
57
57
  "nullable": false
58
58
  }
59
59
  }
@@ -72,18 +72,18 @@ Content:
72
72
  },
73
73
  {
74
74
  "name": "selectSourceFile",
75
- "description": "Selects a source file. Use this when asked about files on the page. Use listSourceFiles if you don't know the full path name.",
75
+ "description": "Selects a source file. Use this when asked about files on the page. Use listSourceFiles to find the file ID.",
76
76
  "parameters": {
77
77
  "type": 6,
78
78
  "description": "",
79
79
  "nullable": true,
80
80
  "required": [
81
- "name"
81
+ "id"
82
82
  ],
83
83
  "properties": {
84
- "name": {
85
- "type": 1,
86
- "description": "The full path name of the file you want to select.",
84
+ "id": {
85
+ "type": 3,
86
+ "description": "The id (URL) of the file you want to select.",
87
87
  "nullable": false
88
88
  }
89
89
  }