chrome-devtools-frontend 1.0.1708524 → 1.0.1709383
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +2 -0
- package/front_end/core/common/Color.ts +6 -0
- package/front_end/core/common/VersionController.ts +0 -53
- package/front_end/core/root/Runtime.ts +0 -41
- package/front_end/core/sdk/CSSModel.ts +57 -0
- package/front_end/core/sdk/CSSPropertyParser.ts +10 -17
- package/front_end/core/sdk/DebuggerModel.ts +90 -56
- package/front_end/core/sdk/NetworkRequest.ts +37 -15
- package/front_end/core/sdk/OverlayModel.ts +47 -0
- package/front_end/core/sdk/PageResourceLoader.ts +26 -6
- package/front_end/core/sdk/SourceMap.ts +38 -1
- package/front_end/core/sdk/SourceMapScopesInfo.ts +89 -0
- package/front_end/core/text_utils/TextUtils.ts +1 -1
- package/front_end/entrypoints/devtools_app/devtools_app.ts +1 -0
- package/front_end/entrypoints/main/MainImpl.ts +2 -21
- package/front_end/generated/InspectorBackendCommands.ts +2 -1
- package/front_end/generated/SupportedCSSProperties.ts +1 -1
- package/front_end/generated/protocol.ts +8 -3
- package/front_end/models/ai_assistance/AiAgent2.ts +126 -2
- package/front_end/models/ai_assistance/AiConversation.ts +2 -2
- package/front_end/models/ai_assistance/AiUtils.ts +4 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +64 -13
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +4 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +257 -2
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +1 -1
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -2
- package/front_end/models/ai_assistance/contexts/{AccessibilityContext.snapshot.txt → LighthouseContext.snapshot.txt} +23 -2
- package/front_end/models/ai_assistance/contexts/{AccessibilityContext.ts → LighthouseContext.ts} +24 -5
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +8 -18
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +2 -2
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +81 -103
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +202 -15
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +6 -0
- package/front_end/models/ai_assistance/tools/GetCookieValues.ts +3 -0
- package/front_end/models/ai_assistance/tools/GetDetailedCallTree.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetInsightDetails.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +2 -1
- package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetStorageBreakdown.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetStorageValues.ts +3 -0
- package/front_end/models/ai_assistance/tools/GetStyles.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetTraceEventByKey.ts +3 -1
- package/front_end/models/ai_assistance/tools/GetTraceFunctionCode.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetTraceMainThreadSummary.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetTraceNetworkSummary.ts +2 -0
- package/front_end/models/ai_assistance/tools/GetTraceResourceContent.ts +2 -0
- package/front_end/models/ai_assistance/tools/ListCookies.ts +2 -0
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +2 -0
- package/front_end/models/ai_assistance/tools/ListPageOrigins.ts +2 -0
- package/front_end/models/ai_assistance/tools/ListSources.ts +2 -0
- package/front_end/models/ai_assistance/tools/ListStorageKeys.ts +2 -0
- package/front_end/models/ai_assistance/tools/RecordPerformanceTrace.ts +2 -0
- package/front_end/models/ai_assistance/tools/ResolveDevtoolsNodePath.ts +2 -0
- package/front_end/models/ai_assistance/tools/RunLighthouse.ts +14 -9
- package/front_end/models/ai_assistance/tools/SelectTraceEventByKey.ts +2 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +53 -0
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +37 -10
- package/front_end/models/bindings/SourceMapStepping.ts +50 -0
- package/front_end/models/bindings/bindings.ts +2 -0
- package/front_end/models/emulation/DeviceModeModel.ts +85 -62
- package/front_end/models/har/Importer.ts +2 -3
- package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -1
- package/front_end/models/source_map_scopes/NamesResolver.ts +30 -5
- package/front_end/models/trace/LanternComputationData.ts +8 -0
- package/front_end/models/trace/Processor.ts +2 -1
- package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +7 -2
- package/front_end/models/trace/lantern/graph/NetworkNode.ts +14 -0
- package/front_end/models/trace/lantern/graph/PageDependencyGraph.ts +1 -1
- package/front_end/models/trace/lantern/simulation/ConnectionPool.ts +4 -4
- package/front_end/models/trace/lantern/simulation/Simulator.ts +6 -2
- package/front_end/models/trace/lantern/simulation/TCPConnection.ts +12 -12
- package/front_end/models/trace/lantern/types/Lantern.ts +8 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -12
- package/front_end/panels/ai_assistance/components/ChatInput.ts +1 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +121 -13
- package/front_end/panels/ai_assistance/components/chatMessage.css +47 -0
- package/front_end/panels/application/BackgroundServiceView.ts +31 -33
- package/front_end/panels/application/IndexedDBModel.ts +8 -20
- package/front_end/panels/application/IndexedDBViews.ts +2 -6
- package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +8 -8
- package/front_end/panels/application/ServiceWorkersView.ts +44 -52
- package/front_end/panels/application/WebMCPView.ts +50 -50
- package/front_end/panels/comments/CommentsPane.ts +266 -0
- package/front_end/panels/comments/comments-meta.ts +47 -0
- package/front_end/panels/comments/comments.ts +9 -0
- package/front_end/panels/comments/commentsPane.css +206 -0
- package/front_end/panels/common/CommentsStatusBarPill.ts +3 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +1 -2
- package/front_end/panels/console/ConsoleViewport.ts +1 -1
- package/front_end/panels/console/SymbolizedErrorWidget.ts +18 -9
- package/front_end/panels/elements/CSSValueTraceView.ts +4 -4
- package/front_end/panels/elements/ComputedStyleWidget.ts +46 -42
- package/front_end/panels/elements/DOMPath.ts +11 -1
- package/front_end/panels/elements/DOMTreeContextMenu.ts +15 -0
- package/front_end/panels/elements/DOMTreeWidget.ts +30 -20
- package/front_end/panels/elements/ElementsPanel.ts +14 -11
- package/front_end/panels/elements/ElementsTreeElement.ts +24 -18
- package/front_end/panels/elements/EventListenersWidget.ts +5 -3
- package/front_end/panels/elements/InspectElementModeController.ts +6 -3
- package/front_end/panels/elements/LayoutPane.ts +3 -3
- package/front_end/panels/elements/PropertyRenderer.ts +132 -87
- package/front_end/panels/elements/StandaloneStylesContainer.ts +7 -3
- package/front_end/panels/elements/StylePropertiesSection.ts +49 -4
- package/front_end/panels/elements/StylePropertyTreeElement.ts +58 -50
- package/front_end/panels/elements/StylesContainer.ts +2 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +75 -16
- package/front_end/panels/elements/components/CSSPropertyDocsView.ts +2 -1
- package/front_end/panels/elements/elements-meta.ts +24 -75
- package/front_end/panels/emulation/DeviceModeToolbar.ts +5 -2
- package/front_end/panels/emulation/DeviceModeView.ts +5 -2
- package/front_end/panels/emulation/emulation-meta.ts +3 -8
- package/front_end/panels/layer_viewer/Layers3DView.ts +8 -3
- package/front_end/panels/layer_viewer/layer_viewer-meta.ts +2 -5
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +13 -3
- package/front_end/panels/network/NetworkConfigView.ts +30 -3
- package/front_end/panels/network/NetworkLogView.ts +7 -5
- package/front_end/panels/network/NetworkPanel.ts +4 -3
- package/front_end/panels/network/NetworkWaterfallColumn.ts +7 -4
- package/front_end/panels/network/network-meta.ts +23 -34
- package/front_end/panels/profiler/HeapProfileView.ts +20 -24
- package/front_end/panels/profiler/ProfilesPanel.ts +8 -3
- package/front_end/panels/screencast/ScreencastView.ts +6 -4
- package/front_end/panels/sources/SourcesView.ts +1 -1
- package/front_end/panels/sources/TabbedEditorContainer.ts +36 -32
- package/front_end/panels/timeline/TimelineHistoryManager.ts +2 -4
- package/front_end/panels/timeline/components/LiveMetricsView.ts +7 -20
- package/front_end/panels/timeline/components/MetricCard.ts +262 -315
- package/front_end/panels/timeline/components/liveMetricsView.css +4 -0
- package/front_end/panels/timeline/components/metricCard.css +2 -24
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +33 -17
- package/front_end/panels/timeline/overlays/components/TimeRangeOverlay.ts +182 -130
- package/front_end/panels/timeline/overlays/components/timeRangeOverlay.css +76 -74
- package/front_end/panels/whats_new/WhatsNewImpl.ts +2 -1
- package/front_end/panels/whats_new/whats_new-meta.ts +2 -5
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/web-vitals/README.chromium +2 -2
- package/front_end/third_party/web-vitals/package/README.md +5 -3
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +8 -5
- package/front_end/third_party/web-vitals/package/package.json +1 -1
- package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +1 -1
- package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +9 -5
- package/front_end/third_party/web-vitals/rebuild.sh +2 -2
- package/front_end/ui/components/text_editor/config.ts +2 -1
- package/front_end/ui/legacy/TabbedPane.ts +67 -12
- package/front_end/ui/legacy/Toolbar.ts +29 -9
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +93 -31
- package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +15 -7
- package/front_end/ui/legacy/components/utils/Linkifier.ts +4 -0
- package/front_end/ui/legacy/tabbedPane.css +12 -8
- package/front_end/ui/settings/ElementsSettings.ts +93 -0
- package/front_end/ui/settings/EmulationSettings.ts +17 -0
- package/front_end/ui/settings/LayerViewerSettings.ts +12 -0
- package/front_end/ui/settings/NetworkSettings.ts +26 -0
- package/front_end/ui/settings/WhatsNewSettings.ts +11 -0
- package/front_end/ui/settings/settings.ts +10 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
- package/inspector_overlay/highlight_anchor.ts +1 -1
- package/package.json +1 -1
|
@@ -662,6 +662,18 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
|
|
|
662
662
|
color: Common.Color.PageHighlight.LayoutLine.toProtocolRGBA(),
|
|
663
663
|
},
|
|
664
664
|
};
|
|
665
|
+
|
|
666
|
+
highlightConfig.imcbHighlightConfig = {
|
|
667
|
+
imcbBorderColor: Common.Color.PageHighlight.AnchorIMCB.toProtocolRGBA(),
|
|
668
|
+
imcbBackgroundColor: Common.Color.PageHighlight.AnchorIMCBBackground.toProtocolRGBA(),
|
|
669
|
+
insetsBackgroundColor: Common.Color.PageHighlight.AnchorInsetsBackground.toProtocolRGBA(),
|
|
670
|
+
insetsHatchColor: Common.Color.PageHighlight.AnchorInsetsHatch.toProtocolRGBA(),
|
|
671
|
+
anchorBorderColor: Common.Color.PageHighlight.AnchorTarget.toProtocolRGBA(),
|
|
672
|
+
anchorBackgroundColor: Common.Color.PageHighlight.AnchorTargetBackground.toProtocolRGBA(),
|
|
673
|
+
showPositionAreaGrid: true,
|
|
674
|
+
positionAreaGridLineColor: Common.Color.PageHighlight.AnchorTarget.toProtocolRGBA(),
|
|
675
|
+
positionAreaActiveRegionColor: Common.Color.PageHighlight.AnchorTargetBackground.toProtocolRGBA(),
|
|
676
|
+
};
|
|
665
677
|
}
|
|
666
678
|
|
|
667
679
|
if (mode.endsWith('gap')) {
|
|
@@ -793,6 +805,41 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
|
|
|
793
805
|
};
|
|
794
806
|
}
|
|
795
807
|
|
|
808
|
+
const baseImcbHighlightConfig = {
|
|
809
|
+
imcbBorderColor: Common.Color.PageHighlight.AnchorIMCB.toProtocolRGBA(),
|
|
810
|
+
imcbBackgroundColor: Common.Color.PageHighlight.AnchorIMCBBackground.toProtocolRGBA(),
|
|
811
|
+
anchorBorderColor: Common.Color.PageHighlight.AnchorTarget.toProtocolRGBA(),
|
|
812
|
+
anchorBackgroundColor: Common.Color.PageHighlight.AnchorTargetBackground.toProtocolRGBA(),
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
if (mode === 'anchor-positioning') {
|
|
816
|
+
highlightConfig.imcbHighlightConfig = {
|
|
817
|
+
...baseImcbHighlightConfig,
|
|
818
|
+
insetsBackgroundColor: Common.Color.PageHighlight.AnchorInsetsBackground.toProtocolRGBA(),
|
|
819
|
+
insetsHatchColor: Common.Color.PageHighlight.AnchorInsetsHatch.toProtocolRGBA(),
|
|
820
|
+
showPositionAreaGrid: true,
|
|
821
|
+
positionAreaGridLineColor: Common.Color.PageHighlight.AnchorTarget.toProtocolRGBA(),
|
|
822
|
+
positionAreaActiveRegionColor: Common.Color.PageHighlight.AnchorTargetBackground.toProtocolRGBA(),
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (mode === 'position-area') {
|
|
827
|
+
highlightConfig.imcbHighlightConfig = {
|
|
828
|
+
...baseImcbHighlightConfig,
|
|
829
|
+
showPositionAreaGrid: true,
|
|
830
|
+
positionAreaGridLineColor: Common.Color.PageHighlight.AnchorTarget.toProtocolRGBA(),
|
|
831
|
+
positionAreaActiveRegionColor: Common.Color.PageHighlight.AnchorTargetBackground.toProtocolRGBA(),
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (mode === 'insets') {
|
|
836
|
+
highlightConfig.imcbHighlightConfig = {
|
|
837
|
+
...baseImcbHighlightConfig,
|
|
838
|
+
insetsBackgroundColor: Common.Color.PageHighlight.AnchorInsetsBackground.toProtocolRGBA(),
|
|
839
|
+
insetsHatchColor: Common.Color.PageHighlight.AnchorInsetsHatch.toProtocolRGBA(),
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
|
|
796
843
|
return highlightConfig;
|
|
797
844
|
}
|
|
798
845
|
|
|
@@ -317,6 +317,29 @@ export class PageResourceLoader extends Common.ObjectWrapper.ObjectWrapper<Event
|
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
#resolveFrameTarget(initiator: PageResourceLoadInitiator): {
|
|
321
|
+
frameTarget: Target|null,
|
|
322
|
+
frameId: Protocol.Page.FrameId|null,
|
|
323
|
+
} {
|
|
324
|
+
let frameTarget: Target|null = initiator.target;
|
|
325
|
+
let parentFrameId: Protocol.Page.FrameId|null = null;
|
|
326
|
+
while (frameTarget && !frameTarget.model(ResourceTreeModel)) {
|
|
327
|
+
parentFrameId = parentFrameId ?? frameTarget.targetInfo()?.parentFrameId ?? null;
|
|
328
|
+
frameTarget = frameTarget.parentTarget();
|
|
329
|
+
}
|
|
330
|
+
const frameId = initiator.frameId ?? parentFrameId ?? frameTarget?.model(ResourceTreeModel)?.mainFrame?.id ?? null;
|
|
331
|
+
return {frameTarget, frameId};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
#isSameOriginWithPrimaryPage(frameTarget: Target|null, frameId: Protocol.Page.FrameId|null): boolean {
|
|
335
|
+
const primaryFrame = this.#targetManager.primaryPageTarget()?.model(ResourceTreeModel)?.mainFrame;
|
|
336
|
+
const initiatorFrame = frameId ? frameTarget?.model(ResourceTreeModel)?.frameForId(frameId) : null;
|
|
337
|
+
if (!primaryFrame || !initiatorFrame) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
return initiatorFrame.securityOrigin().isSameOriginWith(primaryFrame.securityOrigin());
|
|
341
|
+
}
|
|
342
|
+
|
|
320
343
|
private async dispatchLoad(
|
|
321
344
|
url: Platform.DevToolsPath.UrlString, initiator: PageResourceLoadInitiator, isBinary: boolean): Promise<{
|
|
322
345
|
success: boolean,
|
|
@@ -343,11 +366,7 @@ export class PageResourceLoader extends Common.ObjectWrapper.ObjectWrapper<Event
|
|
|
343
366
|
// directive is present. A null/error response keeps the guard armed so that a
|
|
344
367
|
// detached-frame or protocol-error path cannot fall through to loadFromHostBindings.
|
|
345
368
|
let mustEnforceCSP = isHttp;
|
|
346
|
-
|
|
347
|
-
while (frameTarget && !frameTarget.model(ResourceTreeModel)) {
|
|
348
|
-
frameTarget = frameTarget.parentTarget();
|
|
349
|
-
}
|
|
350
|
-
const frameId = initiator.frameId ?? frameTarget?.model(ResourceTreeModel)?.mainFrame?.id ?? null;
|
|
369
|
+
const {frameTarget, frameId} = this.#resolveFrameTarget(initiator);
|
|
351
370
|
if (isHttp && frameTarget) {
|
|
352
371
|
const networkManager = frameTarget.model(NetworkManager);
|
|
353
372
|
if (networkManager) {
|
|
@@ -366,7 +385,8 @@ export class PageResourceLoader extends Common.ObjectWrapper.ObjectWrapper<Event
|
|
|
366
385
|
} catch (e) {
|
|
367
386
|
if (e instanceof Error) {
|
|
368
387
|
Host.userMetrics.developerResourceLoaded(Host.UserMetrics.DeveloperResourceLoaded.LOAD_THROUGH_PAGE_FAILURE);
|
|
369
|
-
if (mustEnforceCSP ||
|
|
388
|
+
if (mustEnforceCSP || !this.#isSameOriginWithPrimaryPage(frameTarget, frameId) ||
|
|
389
|
+
e.message.includes('CSP violation')) {
|
|
370
390
|
return {
|
|
371
391
|
success: false,
|
|
372
392
|
content: '',
|
|
@@ -12,7 +12,12 @@ import {scopeTreeForScript} from './ScopeTreeCache.js';
|
|
|
12
12
|
import type {Script} from './Script.js';
|
|
13
13
|
import {buildOriginalScopes, decodePastaRanges, type NamedFunctionRange} from './SourceMapFunctionRanges.js';
|
|
14
14
|
import {decodeRangeMappings} from './SourceMapRangeMappings.js';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
type PositionRange,
|
|
17
|
+
type RawFrameTranslation,
|
|
18
|
+
scriptRelativePosition,
|
|
19
|
+
SourceMapScopesInfo,
|
|
20
|
+
} from './SourceMapScopesInfo.js';
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* Type of the base source map JSON object, which contains the sources and the mappings at the very least, plus
|
|
@@ -250,6 +255,16 @@ export class SourceMap {
|
|
|
250
255
|
return this.#scopesInfo !== null && !this.#scopesInfo.isEmpty();
|
|
251
256
|
}
|
|
252
257
|
|
|
258
|
+
/**
|
|
259
|
+
* True iff the scopes come from the source map itself (encoded `scopes`), not from the AST fallback or from an
|
|
260
|
+
* extension.
|
|
261
|
+
*/
|
|
262
|
+
hasEncodedScopeInfo(): boolean {
|
|
263
|
+
this.#ensureSourceMapProcessed();
|
|
264
|
+
return this.#scopesInfo !== null && this.#scopesFallbackPromise === undefined &&
|
|
265
|
+
this.#scopesInfo.hasGeneratedRanges();
|
|
266
|
+
}
|
|
267
|
+
|
|
253
268
|
waitForScopeInfo(): Promise<void> {
|
|
254
269
|
this.#ensureSourceMapProcessed();
|
|
255
270
|
return this.#scopesFallbackPromise ?? Promise.resolve();
|
|
@@ -872,6 +887,28 @@ export class SourceMap {
|
|
|
872
887
|
this.#ensureSourceMapProcessed();
|
|
873
888
|
return this.#scopesInfo?.translateRawFrame(generatedLine, generatedColumn) ?? null;
|
|
874
889
|
}
|
|
890
|
+
|
|
891
|
+
/** See {@link SourceMapScopesInfo.inlinedFunctionRange}. `null` without encoded scopes. */
|
|
892
|
+
inlinedFunctionRange(generatedLine: number, generatedColumn: number): PositionRange|null {
|
|
893
|
+
return this.hasEncodedScopeInfo() ? this.#scopesInfo?.inlinedFunctionRange(generatedLine, generatedColumn) ?? null :
|
|
894
|
+
null;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/** See {@link SourceMapScopesInfo.inlinedCalleeRanges}. Empty without encoded scopes. */
|
|
898
|
+
inlinedCalleeRanges(generatedLine: number, generatedColumn: number): PositionRange[] {
|
|
899
|
+
return this.hasEncodedScopeInfo() ? this.#scopesInfo?.inlinedCalleeRanges(generatedLine, generatedColumn) ?? [] :
|
|
900
|
+
[];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/** See {@link SourceMapScopesInfo.hasOutlinedFunctions}. False without encoded scopes. */
|
|
904
|
+
hasOutlinedFunctions(): boolean {
|
|
905
|
+
return this.hasEncodedScopeInfo() && (this.#scopesInfo?.hasOutlinedFunctions() ?? false);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/** See {@link SourceMapScopesInfo.artificialFunctionRanges}. Empty without encoded scopes. */
|
|
909
|
+
artificialFunctionRanges(): PositionRange[] {
|
|
910
|
+
return this.hasEncodedScopeInfo() ? this.#scopesInfo?.artificialFunctionRanges() ?? [] : [];
|
|
911
|
+
}
|
|
875
912
|
}
|
|
876
913
|
|
|
877
914
|
/** @returns a copy of the {@link entry} that is marked as a range mapping. */
|
|
@@ -215,6 +215,10 @@ export class SourceMapScopesInfo {
|
|
|
215
215
|
return noScopes && !this.#generatedRanges.length;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
hasGeneratedRanges(): boolean {
|
|
219
|
+
return this.#generatedRanges.length > 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
218
222
|
addOriginalScopesAtIndex(sourceIdx: number, scopes: ScopesCodec.OriginalScope[]): void {
|
|
219
223
|
if (!this.#originalScopes[sourceIdx]?.length) {
|
|
220
224
|
this.#originalScopes[sourceIdx] = scopes;
|
|
@@ -561,6 +565,91 @@ export class SourceMapScopesInfo {
|
|
|
561
565
|
|
|
562
566
|
return result;
|
|
563
567
|
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @returns the body of the innermost inlined function at the position (the innermost range with a `callSite`
|
|
571
|
+
* within the generated function), or null if the position is not inside an inlined function.
|
|
572
|
+
*
|
|
573
|
+
* The innermost inlined function is the logical frame the position belongs to, i.e. the analogue of the top frame
|
|
574
|
+
* of a real call stack. Stepping over its body therefore goes up exactly one logical frame: into the caller, which
|
|
575
|
+
* may itself be inlined. An outer range would leave several logical frames at once.
|
|
576
|
+
*/
|
|
577
|
+
inlinedFunctionRange(generatedLine: number, generatedColumn: number): PositionRange|null {
|
|
578
|
+
const rangeChain = this.#findGeneratedRangeChain(generatedLine, generatedColumn);
|
|
579
|
+
for (let i = rangeChain.length - 1; i >= 0 && !rangeChain[i].isStackFrame; --i) {
|
|
580
|
+
if (rangeChain[i].callSite) {
|
|
581
|
+
return {start: rangeChain[i].start, end: rangeChain[i].end};
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @returns the bodies of all functions that were inlined directly into the logical function at the position
|
|
589
|
+
* (the innermost inlined function, or else the generated function). Doesn't descend into inlined
|
|
590
|
+
* functions or nested generated functions.
|
|
591
|
+
*/
|
|
592
|
+
inlinedCalleeRanges(generatedLine: number, generatedColumn: number): PositionRange[] {
|
|
593
|
+
const rangeChain = this.#findGeneratedRangeChain(generatedLine, generatedColumn);
|
|
594
|
+
let body: ScopesCodec.GeneratedRange|undefined;
|
|
595
|
+
for (let i = rangeChain.length - 1; i >= 0 && !body; --i) {
|
|
596
|
+
if (rangeChain[i].callSite || rangeChain[i].isStackFrame) {
|
|
597
|
+
body = rangeChain[i];
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const result: PositionRange[] = [];
|
|
601
|
+
(function walk(range: ScopesCodec.GeneratedRange) {
|
|
602
|
+
for (const child of range.children) {
|
|
603
|
+
if (child.isStackFrame) {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
if (child.callSite) {
|
|
607
|
+
result.push({start: child.start, end: child.end});
|
|
608
|
+
} else {
|
|
609
|
+
walk(child);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
})(body ?? {children: this.#generatedRanges} as ScopesCodec.GeneratedRange);
|
|
613
|
+
return result;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* @returns true, iff any generated function is outlined, i.e. marked as "hidden" but with a definition (see
|
|
618
|
+
* {@link GeneratedFrameKind.OUTLINED}). Hidden functions without a definition are compiler helpers.
|
|
619
|
+
*/
|
|
620
|
+
hasOutlinedFunctions(): boolean {
|
|
621
|
+
const hasOutlined = (ranges: ScopesCodec.GeneratedRange[]): boolean =>
|
|
622
|
+
ranges.some(range => (range.isStackFrame && range.isHidden && range.originalScope !== undefined) ||
|
|
623
|
+
hasOutlined(range.children));
|
|
624
|
+
return hasOutlined(this.#generatedRanges);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* @returns the "artificial" generated functions (in the DWARF sense): functions that contain no authored code at all
|
|
629
|
+
* (no original scope anywhere in their subtree), e.g. compiler helpers. Sorted by start position,
|
|
630
|
+
* non-overlapping.
|
|
631
|
+
*/
|
|
632
|
+
artificialFunctionRanges(): PositionRange[] {
|
|
633
|
+
const hasOriginalScope = (range: ScopesCodec.GeneratedRange): boolean =>
|
|
634
|
+
range.originalScope !== undefined || range.children.some(hasOriginalScope);
|
|
635
|
+
const result: PositionRange[] = [];
|
|
636
|
+
(function walk(ranges: ScopesCodec.GeneratedRange[]) {
|
|
637
|
+
for (const range of ranges) {
|
|
638
|
+
if (range.isStackFrame && !hasOriginalScope(range)) {
|
|
639
|
+
result.push({start: range.start, end: range.end});
|
|
640
|
+
} else {
|
|
641
|
+
walk(range.children);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
})(this.#generatedRanges);
|
|
645
|
+
return result;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** A range of generated positions, relative to the start of the script. `end` is exclusive. */
|
|
650
|
+
export interface PositionRange {
|
|
651
|
+
readonly start: ScopesCodec.Position;
|
|
652
|
+
readonly end: ScopesCodec.Position;
|
|
564
653
|
}
|
|
565
654
|
|
|
566
655
|
/**
|
|
@@ -9,7 +9,7 @@ import {SearchMatch} from './ContentProvider.js';
|
|
|
9
9
|
import type {Text} from './Text.js';
|
|
10
10
|
|
|
11
11
|
const KEY_VALUE_FILTER_REGEXP = /(?:^|\s)(\-)?([\w\-]+):([^\s]+)/;
|
|
12
|
-
const REGEXP_FILTER_REGEXP = /(?:^|\s)(\-)?\/([^\/\\]+
|
|
12
|
+
const REGEXP_FILTER_REGEXP = /(?:^|\s)(\-)?\/((?:[^\/\\]|\\.)+)\//;
|
|
13
13
|
const TEXT_FILTER_REGEXP = /(?:^|\s)(\-)?([^\s]+)/;
|
|
14
14
|
const SPACE_CHAR_REGEXP = /\s/;
|
|
15
15
|
|
|
@@ -2,6 +2,7 @@
|
|
|
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
|
import '../shell/shell.js';
|
|
5
|
+
import '../../panels/comments/comments-meta.js';
|
|
5
6
|
import '../../panels/css_overview/css_overview-meta.js';
|
|
6
7
|
import '../../panels/elements/elements-meta.js';
|
|
7
8
|
import '../../panels/browser_debugger/browser_debugger-meta.js';
|
|
@@ -223,8 +223,6 @@ export class MainImpl {
|
|
|
223
223
|
this.#universe.settings.resolve(SDK.SDKSettings.cacheDisabledSettingDescriptor).setRequiresUserAction(true);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
Root.Runtime.experiments.removeAllExperimentsFromLocalStorage();
|
|
227
|
-
|
|
228
226
|
await this.requestAndRegisterLocaleData();
|
|
229
227
|
|
|
230
228
|
Host.userMetrics.syncSetting(
|
|
@@ -352,23 +350,10 @@ export class MainImpl {
|
|
|
352
350
|
return {syncedStorage, globalStorage, localStorage};
|
|
353
351
|
}
|
|
354
352
|
|
|
355
|
-
// TODO(crbug.com/464173054) remove after M156
|
|
356
|
-
#migrateValueFromLegacyExperiment(legacyExperimentName: Root.ExperimentNames.ExperimentName,
|
|
357
|
-
experiment: Root.Runtime.Experiment): void {
|
|
358
|
-
const value = Root.Runtime.experiments.getValueFromStorage(legacyExperimentName);
|
|
359
|
-
if (value !== undefined && experiment.aboutFlag) {
|
|
360
|
-
// Set the experiment to the same value as the legacy experiment.
|
|
361
|
-
experiment.setEnabled(value);
|
|
362
|
-
// Set the chrome flag to the same value as the legacy experiment.
|
|
363
|
-
Host.InspectorFrontendHost.InspectorFrontendHostInstance.setChromeFlag(experiment.aboutFlag, value);
|
|
364
|
-
// The legacy experiment will be cleaned up by `removeAllExperimentsFromLocalStorage`.
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
353
|
#initializeExperiments(): void {
|
|
369
354
|
const enableProtocolMonitor = (Root.Runtime.hostConfig.devToolsProtocolMonitor?.enabled ?? false) ||
|
|
370
355
|
Boolean(Root.Runtime.Runtime.queryParam('isChromeForTesting'));
|
|
371
|
-
|
|
356
|
+
Root.Runtime.experiments.register({
|
|
372
357
|
name: Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR,
|
|
373
358
|
title: 'Protocol Monitor',
|
|
374
359
|
aboutFlag: 'devtools-protocol-monitor',
|
|
@@ -377,19 +362,15 @@ export class MainImpl {
|
|
|
377
362
|
docLink: 'https://developer.chrome.com/blog/new-in-devtools-92/#protocol-monitor' as
|
|
378
363
|
Platform.DevToolsPath.UrlString,
|
|
379
364
|
});
|
|
380
|
-
this.#migrateValueFromLegacyExperiment(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR,
|
|
381
|
-
protocolMonitorExperiment);
|
|
382
365
|
|
|
383
366
|
// Debugging
|
|
384
|
-
|
|
367
|
+
Root.Runtime.experiments.register({
|
|
385
368
|
name: Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS,
|
|
386
369
|
title: 'Instrumentation breakpoints',
|
|
387
370
|
aboutFlag: 'devtools-instrumentation-breakpoints',
|
|
388
371
|
isEnabled: Root.Runtime.hostConfig.devToolsInstrumentationBreakpoints?.enabled ?? false,
|
|
389
372
|
requiresChromeRestart: false,
|
|
390
373
|
});
|
|
391
|
-
this.#migrateValueFromLegacyExperiment(Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS,
|
|
392
|
-
instrumentationBreakpointsExperiment);
|
|
393
374
|
|
|
394
375
|
Root.Runtime.experiments.register({
|
|
395
376
|
name: Root.ExperimentNames.ExperimentName.DURABLE_MESSAGES,
|
|
@@ -1520,6 +1520,7 @@ inspectorBackend.registerType("WebMCP.RemovedTool", [{"name": "name", "type": "s
|
|
|
1520
1520
|
|
|
1521
1521
|
// Debugger.
|
|
1522
1522
|
inspectorBackend.registerEnum("Debugger.ScopeType", {Global: "global", Local: "local", With: "with", Closure: "closure", Catch: "catch", Block: "block", Script: "script", Eval: "eval", Module: "module", WasmExpressionStack: "wasm-expression-stack"});
|
|
1523
|
+
inspectorBackend.registerEnum("Debugger.ScopeEmptyReason", {NoVariables: "no-variables", AllUnavailable: "all-unavailable"});
|
|
1523
1524
|
inspectorBackend.registerEnum("Debugger.BreakLocationType", {DebuggerStatement: "debuggerStatement", Call: "call", Return: "return"});
|
|
1524
1525
|
inspectorBackend.registerEnum("Debugger.ScriptLanguage", {JavaScript: "JavaScript", WebAssembly: "WebAssembly"});
|
|
1525
1526
|
inspectorBackend.registerEnum("Debugger.DebugSymbolsType", {SourceMap: "SourceMap", EmbeddedDWARF: "EmbeddedDWARF", ExternalDWARF: "ExternalDWARF"});
|
|
@@ -1570,7 +1571,7 @@ inspectorBackend.registerType("Debugger.Location", [{"name": "scriptId", "type":
|
|
|
1570
1571
|
inspectorBackend.registerType("Debugger.ScriptPosition", [{"name": "lineNumber", "type": "number", "optional": false, "description": "", "typeRef": null}, {"name": "columnNumber", "type": "number", "optional": false, "description": "", "typeRef": null}]);
|
|
1571
1572
|
inspectorBackend.registerType("Debugger.LocationRange", [{"name": "scriptId", "type": "string", "optional": false, "description": "", "typeRef": "Runtime.ScriptId"}, {"name": "start", "type": "object", "optional": false, "description": "", "typeRef": "Debugger.ScriptPosition"}, {"name": "end", "type": "object", "optional": false, "description": "", "typeRef": "Debugger.ScriptPosition"}]);
|
|
1572
1573
|
inspectorBackend.registerType("Debugger.CallFrame", [{"name": "callFrameId", "type": "string", "optional": false, "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused.", "typeRef": "Debugger.CallFrameId"}, {"name": "functionName", "type": "string", "optional": false, "description": "Name of the JavaScript function called on this call frame.", "typeRef": null}, {"name": "functionLocation", "type": "object", "optional": true, "description": "Location in the source code.", "typeRef": "Debugger.Location"}, {"name": "location", "type": "object", "optional": false, "description": "Location in the source code.", "typeRef": "Debugger.Location"}, {"name": "url", "type": "string", "optional": false, "description": "JavaScript script name or url. Deprecated in favor of using the `location.scriptId` to resolve the URL via a previously sent `Debugger.scriptParsed` event.", "typeRef": null}, {"name": "scopeChain", "type": "array", "optional": false, "description": "Scope chain for this call frame.", "typeRef": "Debugger.Scope"}, {"name": "this", "type": "object", "optional": false, "description": "`this` object for this call frame.", "typeRef": "Runtime.RemoteObject"}, {"name": "returnValue", "type": "object", "optional": true, "description": "The value being returned, if the function is at return point.", "typeRef": "Runtime.RemoteObject"}, {"name": "canBeRestarted", "type": "boolean", "optional": true, "description": "Valid only while the VM is paused and indicates whether this frame can be restarted or not. Note that a `true` value here does not guarantee that Debugger#restartFrame with this CallFrameId will be successful, but it is very likely.", "typeRef": null}]);
|
|
1573
|
-
inspectorBackend.registerType("Debugger.Scope", [{"name": "type", "type": "string", "optional": false, "description": "Scope type.", "typeRef": null}, {"name": "object", "type": "object", "optional": false, "description": "Object representing the scope. For `global` and `with` scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties.", "typeRef": "Runtime.RemoteObject"}, {"name": "name", "type": "string", "optional": true, "description": "", "typeRef": null}, {"name": "startLocation", "type": "object", "optional": true, "description": "Location in the source code where scope starts", "typeRef": "Debugger.Location"}, {"name": "endLocation", "type": "object", "optional": true, "description": "Location in the source code where scope ends", "typeRef": "Debugger.Location"}, {"name": "
|
|
1574
|
+
inspectorBackend.registerType("Debugger.Scope", [{"name": "type", "type": "string", "optional": false, "description": "Scope type.", "typeRef": null}, {"name": "object", "type": "object", "optional": false, "description": "Object representing the scope. For `global` and `with` scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties.", "typeRef": "Runtime.RemoteObject"}, {"name": "name", "type": "string", "optional": true, "description": "", "typeRef": null}, {"name": "startLocation", "type": "object", "optional": true, "description": "Location in the source code where scope starts", "typeRef": "Debugger.Location"}, {"name": "endLocation", "type": "object", "optional": true, "description": "Location in the source code where scope ends", "typeRef": "Debugger.Location"}, {"name": "emptyReason", "type": "string", "optional": true, "description": "Present if the scope has no variable values to show. Absent means that the scope declares at least one variable with an available value. Empty scopes are retained in the scope chain because they can be targeted via `evaluateOnCallFrame` (using `scopeNumber`) or matched against scopes in source maps.", "typeRef": null}]);
|
|
1574
1575
|
inspectorBackend.registerType("Debugger.SearchMatch", [{"name": "lineNumber", "type": "number", "optional": false, "description": "Line number in resource content.", "typeRef": null}, {"name": "lineContent", "type": "string", "optional": false, "description": "Line with match content.", "typeRef": null}]);
|
|
1575
1576
|
inspectorBackend.registerType("Debugger.BreakLocation", [{"name": "scriptId", "type": "string", "optional": false, "description": "Script identifier as reported in the `Debugger.scriptParsed`.", "typeRef": "Runtime.ScriptId"}, {"name": "lineNumber", "type": "number", "optional": false, "description": "Line number in the script (0-based).", "typeRef": null}, {"name": "columnNumber", "type": "number", "optional": true, "description": "Column number in the script (0-based).", "typeRef": null}, {"name": "type", "type": "string", "optional": true, "description": "", "typeRef": null}]);
|
|
1576
1577
|
inspectorBackend.registerType("Debugger.WasmDisassemblyChunk", [{"name": "lines", "type": "array", "optional": false, "description": "The next chunk of disassembled lines.", "typeRef": "string"}, {"name": "bytecodeOffsets", "type": "array", "optional": false, "description": "The bytecode offsets describing the start of each line.", "typeRef": "integer"}]);
|
|
@@ -4313,7 +4313,7 @@ export const generatedProperties: CSSProperty[] = [
|
|
|
4313
4313
|
"overlay"
|
|
4314
4314
|
],
|
|
4315
4315
|
"name": "overscroll-container-type",
|
|
4316
|
-
"runtime_flag": "
|
|
4316
|
+
"runtime_flag": "OverscrollAreas",
|
|
4317
4317
|
"runtime_flag_status": "experimental"
|
|
4318
4318
|
},
|
|
4319
4319
|
{
|
|
@@ -20731,6 +20731,11 @@ export namespace Debugger {
|
|
|
20731
20731
|
WasmExpressionStack = 'wasm-expression-stack',
|
|
20732
20732
|
}
|
|
20733
20733
|
|
|
20734
|
+
export const enum ScopeEmptyReason {
|
|
20735
|
+
NoVariables = 'no-variables',
|
|
20736
|
+
AllUnavailable = 'all-unavailable',
|
|
20737
|
+
}
|
|
20738
|
+
|
|
20734
20739
|
/**
|
|
20735
20740
|
* Scope description.
|
|
20736
20741
|
*/
|
|
@@ -20755,13 +20760,13 @@ export namespace Debugger {
|
|
|
20755
20760
|
*/
|
|
20756
20761
|
endLocation?: Location;
|
|
20757
20762
|
/**
|
|
20758
|
-
*
|
|
20759
|
-
*
|
|
20763
|
+
* Present if the scope has no variable values to show. Absent means that
|
|
20764
|
+
* the scope declares at least one variable with an available value.
|
|
20760
20765
|
* Empty scopes are retained in the scope chain because
|
|
20761
20766
|
* they can be targeted via `evaluateOnCallFrame` (using `scopeNumber`) or
|
|
20762
20767
|
* matched against scopes in source maps.
|
|
20763
20768
|
*/
|
|
20764
|
-
|
|
20769
|
+
emptyReason?: ScopeEmptyReason;
|
|
20765
20770
|
}
|
|
20766
20771
|
|
|
20767
20772
|
/**
|
|
@@ -13,13 +13,15 @@ import {
|
|
|
13
13
|
type ContextResponse,
|
|
14
14
|
type ConversationContext,
|
|
15
15
|
type MultimodalInputType,
|
|
16
|
+
type ParsedResponse,
|
|
16
17
|
type RequestOptions,
|
|
17
18
|
ResponseType,
|
|
19
|
+
sanitizeSuggestions,
|
|
18
20
|
} from './agents/AiAgent.js';
|
|
19
21
|
import {type ExecuteJsAgentOptions, executeJsCode} from './agents/ExecuteJavascript.js';
|
|
20
22
|
import {ChangeManager} from './ChangeManager.js';
|
|
21
|
-
import {AccessibilityContext} from './contexts/AccessibilityContext.js';
|
|
22
23
|
import {DOMNodeContext} from './contexts/DOMNodeContext.js';
|
|
24
|
+
import {LighthouseContext} from './contexts/LighthouseContext.js';
|
|
23
25
|
import {PerformanceTraceContext} from './contexts/PerformanceTraceContext.js';
|
|
24
26
|
import {debugLog} from './debug.js';
|
|
25
27
|
import {ExtensionScope} from './ExtensionScope.js';
|
|
@@ -85,6 +87,110 @@ export interface AiAgent2Options extends ExecuteJsAgentOptions {
|
|
|
85
87
|
performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>;
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Matches the follow-up suggestions directive in plain uppercase, at the start
|
|
92
|
+
* of the line or after whitespace: `SUGGESTIONS: ["a"]`, `Done. SUGGESTIONS: ["a"]`.
|
|
93
|
+
* It is case-sensitive, so `Suggestions:` and `DEFAULT_SUGGESTIONS:` do not match.
|
|
94
|
+
* - Group 1: the text before the directive.
|
|
95
|
+
*/
|
|
96
|
+
const PLAIN_SUGGESTIONS_REGEX = /^(.*?)(?:^|\s)SUGGESTIONS:/;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Matches any spelling of the follow-up suggestions directive that is followed
|
|
100
|
+
* by an array ending the line, for example `**Suggestions**: ["a"]`,
|
|
101
|
+
* `- suggestions: ["a"]` or `` `SUGGESTIONS`: ["a"] ``. The keyword is
|
|
102
|
+
* case-insensitive, must be at the start of the line or after whitespace, and
|
|
103
|
+
* can have up to three markdown characters (`*`, `_` or `` ` ``) on each side
|
|
104
|
+
* of it and of the colon. Only markdown characters or whitespace can follow the
|
|
105
|
+
* closing `]`, so `A few suggestions: [see docs](url)` does not match.
|
|
106
|
+
* - Group 1: the text before the directive. It is greedy, so the last keyword
|
|
107
|
+
* on the line is used: `**Suggestions**: [1] Fix. SUGGESTIONS: ["a"]` keeps
|
|
108
|
+
* `**Suggestions**: [1] Fix.` as answer text.
|
|
109
|
+
* - Group 2: the array, from the first `[` after the keyword to the last `]`.
|
|
110
|
+
*/
|
|
111
|
+
const FORMATTED_SUGGESTIONS_REGEX = /^(.*)(?:^|\s)[*_`]{0,3}suggestions[*_`]{0,3}:[*_`]{0,3}\s*`?(\[.*\])[*_`\s]*$/i;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Matches the start of any spelling of the follow-up suggestions directive
|
|
115
|
+
* while it is streaming: the keyword in any case, at the start of the line or
|
|
116
|
+
* after whitespace, with optional markdown characters, followed by `:`. Nothing
|
|
117
|
+
* after the colon is checked, because the array may still be arriving.
|
|
118
|
+
* - Group 1: the text before the directive.
|
|
119
|
+
*/
|
|
120
|
+
const STREAMING_SUGGESTIONS_REGEX = /^(.*?)(?:^|\s)[*_`]{0,3}suggestions[*_`]{0,3}:/i;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Matches a markdown list or heading marker on its own, such as `-`, `1.` or
|
|
124
|
+
* `###`. The marker is dropped when the directive was the only thing after it.
|
|
125
|
+
*/
|
|
126
|
+
const LIST_OR_HEADING_MARKER_REGEX = /^(?:[-*+]|\d+\.|#{1,6})$/;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns the answer text with the directive removed from the last line.
|
|
130
|
+
* `textBeforeDirective` is what the last line contained before the directive.
|
|
131
|
+
*/
|
|
132
|
+
function removeDirectiveFromLastLine(lines: string[], textBeforeDirective: string): string {
|
|
133
|
+
const keptText = textBeforeDirective.trimEnd();
|
|
134
|
+
const lastLine = LIST_OR_HEADING_MARKER_REGEX.test(keptText.trim()) ? '' : keptText;
|
|
135
|
+
return [...lines.slice(0, -1), lastLine].join('\n').trimEnd();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Parses the JSON array of a suggestions directive. Returns `null` if `array`
|
|
140
|
+
* is not valid JSON, and `{suggestions: undefined}` if it is valid but holds no
|
|
141
|
+
* usable suggestions.
|
|
142
|
+
*/
|
|
143
|
+
function parseSuggestionsArray(array: string): {suggestions: [string, ...string[]]|undefined}|null {
|
|
144
|
+
try {
|
|
145
|
+
return {suggestions: sanitizeSuggestions(array)};
|
|
146
|
+
} catch {
|
|
147
|
+
// Invalid JSON: the caller decides whether the line is still a directive.
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Parses a completed response. Only the last line can be the follow-up
|
|
154
|
+
* suggestions directive; every other line is always kept as answer text.
|
|
155
|
+
* 1. If any spelling of the directive is followed by a valid JSON array that
|
|
156
|
+
* ends the line, it is removed and the array becomes the suggestions.
|
|
157
|
+
* 2. Otherwise, if the line contains `SUGGESTIONS:` in plain uppercase, it is
|
|
158
|
+
* removed from the keyword onward even though the array is missing or not
|
|
159
|
+
* valid JSON, and no suggestions are returned.
|
|
160
|
+
* 3. Otherwise, the line is kept unchanged.
|
|
161
|
+
* Text before the directive on the same line is kept.
|
|
162
|
+
*/
|
|
163
|
+
function parseCompletedSuggestions(text: string): ParsedResponse {
|
|
164
|
+
const lines = text.split('\n');
|
|
165
|
+
const lastLine = lines[lines.length - 1];
|
|
166
|
+
|
|
167
|
+
const formatted = lastLine.match(FORMATTED_SUGGESTIONS_REGEX);
|
|
168
|
+
const parsedArray = formatted ? parseSuggestionsArray(formatted[2]) : null;
|
|
169
|
+
if (formatted && parsedArray) {
|
|
170
|
+
const answer = removeDirectiveFromLastLine(lines, formatted[1]);
|
|
171
|
+
return parsedArray.suggestions ? {answer, suggestions: parsedArray.suggestions} : {answer};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const plain = lastLine.match(PLAIN_SUGGESTIONS_REGEX);
|
|
175
|
+
if (plain) {
|
|
176
|
+
return {answer: removeDirectiveFromLastLine(lines, plain[1])};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {answer: text};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Hides a follow-up suggestions directive that is still streaming on the last
|
|
184
|
+
* line, from the keyword onward, without looking at its array. Hiding text by
|
|
185
|
+
* mistake is temporary: the completed response is parsed again by
|
|
186
|
+
* `parseCompletedSuggestions()`.
|
|
187
|
+
*/
|
|
188
|
+
function hideStreamingSuggestions(text: string): string {
|
|
189
|
+
const lines = text.split('\n');
|
|
190
|
+
const match = lines[lines.length - 1].match(STREAMING_SUGGESTIONS_REGEX);
|
|
191
|
+
return match ? removeDirectiveFromLastLine(lines, match[1]) : text;
|
|
192
|
+
}
|
|
193
|
+
|
|
88
194
|
export class AiAgent2 extends AiAgent<unknown> {
|
|
89
195
|
// TODO: The static preamble is a placeholder and will eventually live server-side.
|
|
90
196
|
readonly preamble: string = preamble;
|
|
@@ -236,6 +342,22 @@ Do NOT call \`learnSkills\` for skills that are already loaded.
|
|
|
236
342
|
User query: ${enhancedQuery}`;
|
|
237
343
|
}
|
|
238
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Parses a completed response. Only the last line can be the follow-up
|
|
347
|
+
* suggestions directive. See `parseCompletedSuggestions()`.
|
|
348
|
+
*/
|
|
349
|
+
override parseTextResponse(response: string): ParsedResponse {
|
|
350
|
+
return parseCompletedSuggestions(response.trim());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Parses a response that is still streaming, hiding a suggestions directive
|
|
355
|
+
* on the last line. See `hideStreamingSuggestions()`.
|
|
356
|
+
*/
|
|
357
|
+
protected override parsePartialTextResponse(response: string): ParsedResponse {
|
|
358
|
+
return {answer: hideStreamingSuggestions(response.trim())};
|
|
359
|
+
}
|
|
360
|
+
|
|
239
361
|
override async *
|
|
240
362
|
handleContextDetails(selected: ConversationContext<unknown>|null): AsyncGenerator<ContextResponse, void, void> {
|
|
241
363
|
if (selected) {
|
|
@@ -311,6 +433,8 @@ User query: ${enhancedQuery}`;
|
|
|
311
433
|
description: tool.description,
|
|
312
434
|
parameters: tool.parameters,
|
|
313
435
|
displayInfoFromArgs: tool.displayInfoFromArgs,
|
|
436
|
+
permissionPrompt: tool.permissionPrompt,
|
|
437
|
+
permissionTitle: tool.permissionTitle,
|
|
314
438
|
handler: (args, options) => {
|
|
315
439
|
const context: AllToolsCapabilities = {
|
|
316
440
|
changeManager: this.#changes,
|
|
@@ -319,7 +443,7 @@ User query: ${enhancedQuery}`;
|
|
|
319
443
|
getExecutionContextNode: () => this.#getExecutionContextNode(),
|
|
320
444
|
getTarget: () => this.#getTarget(),
|
|
321
445
|
getOriginLock: () => this.#originLock(),
|
|
322
|
-
getLighthouseReport: () => (this.context instanceof
|
|
446
|
+
getLighthouseReport: () => (this.context instanceof LighthouseContext ? this.context.getItem() : null),
|
|
323
447
|
runLighthouse: async overrides => await (this.#lighthouseRecording?.(overrides) ?? null),
|
|
324
448
|
getPerformanceTraceContext: () => (this.context instanceof PerformanceTraceContext ? this.context : null),
|
|
325
449
|
performanceRecordAndReload: this.#performanceRecordAndReload,
|
|
@@ -33,9 +33,9 @@ import {AiAgent2} from './AiAgent2.js';
|
|
|
33
33
|
import {AiHistoryStorage, ConversationType, type SerializedConversation} from './AiHistoryStorage.js';
|
|
34
34
|
import {isContextSelectionEnabled} from './AiUtils.js';
|
|
35
35
|
import type {ChangeManager} from './ChangeManager.js';
|
|
36
|
-
import {AccessibilityContext} from './contexts/AccessibilityContext.js';
|
|
37
36
|
import {DOMNodeContext} from './contexts/DOMNodeContext.js';
|
|
38
37
|
import {FileContext} from './contexts/FileContext.js';
|
|
38
|
+
import {LighthouseContext} from './contexts/LighthouseContext.js';
|
|
39
39
|
import {PerformanceTraceContext} from './contexts/PerformanceTraceContext.js';
|
|
40
40
|
import {RequestContext} from './contexts/RequestContext.js';
|
|
41
41
|
import {StorageContext} from './contexts/StorageContext.js';
|
|
@@ -207,7 +207,7 @@ export class AiConversation {
|
|
|
207
207
|
this.#updateAgent(ConversationType.NETWORK);
|
|
208
208
|
} else if (updateContext instanceof PerformanceTraceContext) {
|
|
209
209
|
this.#updateAgent(ConversationType.PERFORMANCE);
|
|
210
|
-
} else if (updateContext instanceof
|
|
210
|
+
} else if (updateContext instanceof LighthouseContext) {
|
|
211
211
|
this.#updateAgent(ConversationType.ACCESSIBILITY);
|
|
212
212
|
} else if (updateContext instanceof StorageContext) {
|
|
213
213
|
this.#updateAgent(ConversationType.STORAGE);
|
|
@@ -122,6 +122,10 @@ export function isGeminiBranding(): boolean {
|
|
|
122
122
|
return !!Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
export function isNaturalLanguageInterfaceEnabled(): boolean {
|
|
126
|
+
return Boolean(Root.Runtime.hostConfig.devToolsAiNaturalLanguageInterface?.enabled);
|
|
127
|
+
}
|
|
128
|
+
|
|
125
129
|
/**
|
|
126
130
|
* Returns true if context selection / dynamic context switching is enabled.
|
|
127
131
|
*
|