chrome-devtools-frontend 1.0.1541169 → 1.0.1542501
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/docs/get_the_code.md +9 -0
- package/front_end/Tests.js +6 -1
- package/front_end/core/common/Settings.ts +140 -106
- package/front_end/core/host/UserMetrics.ts +5 -0
- package/front_end/core/sdk/IOModel.ts +1 -4
- package/front_end/core/sdk/ServerSentEventsProtocol.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +18 -7
- package/front_end/foundation/README.md +10 -0
- package/front_end/foundation/Universe.ts +21 -0
- package/front_end/foundation/foundation.ts +7 -0
- package/front_end/generated/SupportedCSSProperties.js +42 -42
- package/front_end/models/ai_assistance/BuiltInAi.ts +2 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +44 -34
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +72 -31
- package/front_end/models/har/Importer.ts +14 -0
- package/front_end/models/issues_manager/IssuesManager.ts +0 -5
- package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
- package/front_end/models/trace/handlers/ScriptsHandler.ts +26 -0
- package/front_end/models/trace/types/TraceEvents.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +117 -103
- package/front_end/panels/ai_assistance/components/ChatView.ts +7 -31
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +1 -1
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +1 -1
- package/front_end/panels/ai_assistance/components/chatView.css +1 -1
- package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -0
- package/front_end/panels/console/ConsolePrompt.ts +8 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +17 -1
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +4 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +3 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +0 -4
- package/front_end/ui/components/markdown_view/MarkdownView.docs.ts +95 -0
- package/front_end/ui/components/markdown_view/MarkdownView.ts +6 -7
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +246 -13
- package/front_end/ui/components/text_editor/config.ts +1 -1
- package/front_end/ui/legacy/Widget.ts +13 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +43 -33
- package/front_end/ui/visual_logging/KnownContextValues.ts +12 -0
- package/mcp/mcp.ts +2 -0
- package/package.json +1 -1
- package/front_end/models/issues_manager/UserReidentificationIssue.ts +0 -72
- package/front_end/models/issues_manager/descriptions/userReidentificationBlocked.md +0 -5
- package/front_end/ui/components/docs/markdown_image/basic.html +0 -19
- package/front_end/ui/components/docs/markdown_image/basic.ts +0 -38
- package/front_end/ui/components/docs/markdown_link/basic.html +0 -17
- package/front_end/ui/components/docs/markdown_link/basic.ts +0 -19
- package/front_end/ui/components/docs/markdown_view/basic.html +0 -25
- package/front_end/ui/components/docs/markdown_view/basic.ts +0 -67
- package/front_end/ui/components/docs/markdown_view/code-block.html +0 -30
- package/front_end/ui/components/docs/markdown_view/code-block.ts +0 -71
|
@@ -317,6 +317,11 @@ export class UserMetrics {
|
|
|
317
317
|
InspectorFrontendHostInstance.recordPerformanceHistogram(
|
|
318
318
|
'DevTools.Insights.TeaserGenerationTime', timeInMilliseconds);
|
|
319
319
|
}
|
|
320
|
+
|
|
321
|
+
consoleInsightTeaserFirstChunkGenerated(timeInMilliseconds: number): void {
|
|
322
|
+
InspectorFrontendHostInstance.recordPerformanceHistogram(
|
|
323
|
+
'DevTools.Insights.TeaserFirstChunkGenerationTime', timeInMilliseconds);
|
|
324
|
+
}
|
|
320
325
|
}
|
|
321
326
|
|
|
322
327
|
/**
|
|
@@ -25,10 +25,7 @@ export class IOModel extends SDKModel<void> {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
async close(handle: Protocol.IO.StreamHandle): Promise<void> {
|
|
28
|
-
|
|
29
|
-
if (result.getError()) {
|
|
30
|
-
console.error('Could not close stream.');
|
|
31
|
-
}
|
|
28
|
+
await this.target().ioAgent().invoke_close({handle});
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
async resolveBlob(objectOrObjectId: Protocol.Runtime.RemoteObjectId|RemoteObject): Promise<string> {
|
|
@@ -35,6 +35,10 @@ export class ServerSentEventsParser {
|
|
|
35
35
|
await this.#decoder.addBase64Chunk(raw);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
addTextChunk(chunk: string): void {
|
|
39
|
+
this.#onTextChunk(chunk);
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
#onTextChunk(chunk: string): void {
|
|
39
43
|
// A line consists of "this.#line" plus a slice of "chunk[start:<next new cr/lf>]".
|
|
40
44
|
let start = 0;
|
|
@@ -41,6 +41,7 @@ import * as Platform from '../../core/platform/platform.js';
|
|
|
41
41
|
import * as ProtocolClient from '../../core/protocol_client/protocol_client.js';
|
|
42
42
|
import * as Root from '../../core/root/root.js';
|
|
43
43
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
44
|
+
import * as Foundation from '../../foundation/foundation.js';
|
|
44
45
|
import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
|
|
45
46
|
import * as AutofillManager from '../../models/autofill_manager/autofill_manager.js';
|
|
46
47
|
import * as Badges from '../../models/badges/badges.js';
|
|
@@ -165,7 +166,17 @@ export class MainImpl {
|
|
|
165
166
|
console.timeStamp('Main._gotPreferences');
|
|
166
167
|
this.#initializeGlobalsForLayoutTests();
|
|
167
168
|
Object.assign(Root.Runtime.hostConfig, config);
|
|
168
|
-
|
|
169
|
+
|
|
170
|
+
const creationOptions: Foundation.Universe.CreationOptions = {
|
|
171
|
+
settingsCreationOptions: {
|
|
172
|
+
...this.createSettingsStorage(prefs),
|
|
173
|
+
settingRegistrations: Common.SettingRegistration.getRegisteredSettings(),
|
|
174
|
+
logSettingAccess: VisualLogging.logSettingAccess,
|
|
175
|
+
runSettingsMigration: !Host.InspectorFrontendHost.isUnderTest(),
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
new Foundation.Universe.Universe(creationOptions);
|
|
179
|
+
|
|
169
180
|
await this.requestAndRegisterLocaleData();
|
|
170
181
|
|
|
171
182
|
Host.userMetrics.syncSetting(Common.Settings.Settings.instance().moduleSetting<boolean>('sync-preferences').get());
|
|
@@ -243,7 +254,11 @@ export class MainImpl {
|
|
|
243
254
|
}
|
|
244
255
|
}
|
|
245
256
|
|
|
246
|
-
|
|
257
|
+
createSettingsStorage(prefs: Record<string, string>): {
|
|
258
|
+
syncedStorage: Common.Settings.SettingsStorage,
|
|
259
|
+
globalStorage: Common.Settings.SettingsStorage,
|
|
260
|
+
localStorage: Common.Settings.SettingsStorage,
|
|
261
|
+
} {
|
|
247
262
|
this.#initializeExperiments();
|
|
248
263
|
let storagePrefix = '';
|
|
249
264
|
if (Host.Platform.isCustomDevtoolsFrontend()) {
|
|
@@ -287,12 +302,8 @@ export class MainImpl {
|
|
|
287
302
|
// setting can't change storage buckets during a single DevTools session.
|
|
288
303
|
const syncedStorage = new Common.Settings.SettingsStorage(prefs, hostSyncedStorage, storagePrefix);
|
|
289
304
|
const globalStorage = new Common.Settings.SettingsStorage(prefs, hostUnsyncedStorage, storagePrefix);
|
|
290
|
-
Common.Settings.Settings.instance(
|
|
291
|
-
{forceNew: true, syncedStorage, globalStorage, localStorage, logSettingAccess: VisualLogging.logSettingAccess});
|
|
292
305
|
|
|
293
|
-
|
|
294
|
-
new Common.Settings.VersionController().updateVersion();
|
|
295
|
-
}
|
|
306
|
+
return {syncedStorage, globalStorage, localStorage};
|
|
296
307
|
}
|
|
297
308
|
|
|
298
309
|
#initializeExperiments(): void {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# DevTools foundation
|
|
2
|
+
|
|
3
|
+
DevTools foundation is the core business logic of DevTools: mainly core/ and models/.
|
|
4
|
+
The difference between "foundation" and the rest of DevTools is
|
|
5
|
+
that the code is targeted not just for the browser, but also the Node.js runtime.
|
|
6
|
+
As such, allowed use of APIs is restricted to what is available in both runtimes.
|
|
7
|
+
|
|
8
|
+
A `DevToolsUniverse` is a concrete, encapsulated instance of "foundation" scoped
|
|
9
|
+
to a single root CDP target. It is valid to create multiple `DevToolsUniverse`
|
|
10
|
+
instances simultaneously.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import * as Common from '../core/common/common.js';
|
|
6
|
+
|
|
7
|
+
export interface CreationOptions {
|
|
8
|
+
// Settings things
|
|
9
|
+
settingsCreationOptions: Common.Settings.SettingsCreationOptions;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Universe {
|
|
13
|
+
constructor(options: CreationOptions) {
|
|
14
|
+
// TODO(crbug.com/458180550): Store instance on a "DevToolsContext" instead.
|
|
15
|
+
// For now the global is fine as we don't anticipate the MCP server to change settings.
|
|
16
|
+
Common.Settings.Settings.instance({
|
|
17
|
+
forceNew: true,
|
|
18
|
+
...options.settingsCreationOptions,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -419,10 +419,10 @@ export const generatedProperties = [
|
|
|
419
419
|
"column-height",
|
|
420
420
|
"column-rule-break",
|
|
421
421
|
"column-rule-color",
|
|
422
|
-
"column-rule-edge-end-
|
|
423
|
-
"column-rule-edge-start-
|
|
424
|
-
"column-rule-interior-end-
|
|
425
|
-
"column-rule-interior-start-
|
|
422
|
+
"column-rule-edge-end-inset",
|
|
423
|
+
"column-rule-edge-start-inset",
|
|
424
|
+
"column-rule-interior-end-inset",
|
|
425
|
+
"column-rule-interior-start-inset",
|
|
426
426
|
"column-rule-style",
|
|
427
427
|
"column-rule-visibility-items",
|
|
428
428
|
"column-rule-width",
|
|
@@ -642,10 +642,10 @@ export const generatedProperties = [
|
|
|
642
642
|
"row-gap",
|
|
643
643
|
"row-rule-break",
|
|
644
644
|
"row-rule-color",
|
|
645
|
-
"row-rule-edge-end-
|
|
646
|
-
"row-rule-edge-start-
|
|
647
|
-
"row-rule-interior-end-
|
|
648
|
-
"row-rule-interior-start-
|
|
645
|
+
"row-rule-edge-end-inset",
|
|
646
|
+
"row-rule-edge-start-inset",
|
|
647
|
+
"row-rule-interior-end-inset",
|
|
648
|
+
"row-rule-interior-start-inset",
|
|
649
649
|
"row-rule-style",
|
|
650
650
|
"row-rule-visibility-items",
|
|
651
651
|
"row-rule-width",
|
|
@@ -1729,28 +1729,28 @@ export const generatedProperties = [
|
|
|
1729
1729
|
},
|
|
1730
1730
|
{
|
|
1731
1731
|
"inherited": false,
|
|
1732
|
-
"name": "column-rule-edge-end-
|
|
1732
|
+
"name": "column-rule-edge-end-inset"
|
|
1733
1733
|
},
|
|
1734
1734
|
{
|
|
1735
1735
|
"inherited": false,
|
|
1736
|
-
"name": "column-rule-edge-start-
|
|
1736
|
+
"name": "column-rule-edge-start-inset"
|
|
1737
1737
|
},
|
|
1738
1738
|
{
|
|
1739
|
-
"
|
|
1740
|
-
|
|
1739
|
+
"longhands": [
|
|
1740
|
+
"column-rule-edge-start-inset",
|
|
1741
|
+
"column-rule-edge-end-inset",
|
|
1742
|
+
"column-rule-interior-start-inset",
|
|
1743
|
+
"column-rule-interior-end-inset"
|
|
1744
|
+
],
|
|
1745
|
+
"name": "column-rule-inset"
|
|
1741
1746
|
},
|
|
1742
1747
|
{
|
|
1743
1748
|
"inherited": false,
|
|
1744
|
-
"name": "column-rule-interior-
|
|
1749
|
+
"name": "column-rule-interior-end-inset"
|
|
1745
1750
|
},
|
|
1746
1751
|
{
|
|
1747
|
-
"
|
|
1748
|
-
|
|
1749
|
-
"column-rule-edge-end-outset",
|
|
1750
|
-
"column-rule-interior-start-outset",
|
|
1751
|
-
"column-rule-interior-end-outset"
|
|
1752
|
-
],
|
|
1753
|
-
"name": "column-rule-outset"
|
|
1752
|
+
"inherited": false,
|
|
1753
|
+
"name": "column-rule-interior-start-inset"
|
|
1754
1754
|
},
|
|
1755
1755
|
{
|
|
1756
1756
|
"keywords": [
|
|
@@ -3738,28 +3738,28 @@ export const generatedProperties = [
|
|
|
3738
3738
|
},
|
|
3739
3739
|
{
|
|
3740
3740
|
"inherited": false,
|
|
3741
|
-
"name": "row-rule-edge-end-
|
|
3741
|
+
"name": "row-rule-edge-end-inset"
|
|
3742
3742
|
},
|
|
3743
3743
|
{
|
|
3744
3744
|
"inherited": false,
|
|
3745
|
-
"name": "row-rule-edge-start-
|
|
3745
|
+
"name": "row-rule-edge-start-inset"
|
|
3746
3746
|
},
|
|
3747
3747
|
{
|
|
3748
|
-
"
|
|
3749
|
-
|
|
3748
|
+
"longhands": [
|
|
3749
|
+
"row-rule-edge-start-inset",
|
|
3750
|
+
"row-rule-edge-end-inset",
|
|
3751
|
+
"row-rule-interior-start-inset",
|
|
3752
|
+
"row-rule-interior-end-inset"
|
|
3753
|
+
],
|
|
3754
|
+
"name": "row-rule-inset"
|
|
3750
3755
|
},
|
|
3751
3756
|
{
|
|
3752
3757
|
"inherited": false,
|
|
3753
|
-
"name": "row-rule-interior-
|
|
3758
|
+
"name": "row-rule-interior-end-inset"
|
|
3754
3759
|
},
|
|
3755
3760
|
{
|
|
3756
|
-
"
|
|
3757
|
-
|
|
3758
|
-
"row-rule-edge-end-outset",
|
|
3759
|
-
"row-rule-interior-start-outset",
|
|
3760
|
-
"row-rule-interior-end-outset"
|
|
3761
|
-
],
|
|
3762
|
-
"name": "row-rule-outset"
|
|
3761
|
+
"inherited": false,
|
|
3762
|
+
"name": "row-rule-interior-start-inset"
|
|
3763
3763
|
},
|
|
3764
3764
|
{
|
|
3765
3765
|
"keywords": [
|
|
@@ -3847,16 +3847,16 @@ export const generatedProperties = [
|
|
|
3847
3847
|
},
|
|
3848
3848
|
{
|
|
3849
3849
|
"longhands": [
|
|
3850
|
-
"row-rule-edge-start-
|
|
3851
|
-
"row-rule-edge-end-
|
|
3852
|
-
"row-rule-interior-start-
|
|
3853
|
-
"row-rule-interior-end-
|
|
3854
|
-
"column-rule-edge-start-
|
|
3855
|
-
"column-rule-edge-end-
|
|
3856
|
-
"column-rule-interior-start-
|
|
3857
|
-
"column-rule-interior-end-
|
|
3858
|
-
],
|
|
3859
|
-
"name": "rule-
|
|
3850
|
+
"row-rule-edge-start-inset",
|
|
3851
|
+
"row-rule-edge-end-inset",
|
|
3852
|
+
"row-rule-interior-start-inset",
|
|
3853
|
+
"row-rule-interior-end-inset",
|
|
3854
|
+
"column-rule-edge-start-inset",
|
|
3855
|
+
"column-rule-edge-end-inset",
|
|
3856
|
+
"column-rule-interior-start-inset",
|
|
3857
|
+
"column-rule-interior-end-inset"
|
|
3858
|
+
],
|
|
3859
|
+
"name": "rule-inset"
|
|
3860
3860
|
},
|
|
3861
3861
|
{
|
|
3862
3862
|
"longhands": [
|
|
@@ -44,7 +44,8 @@ export class BuiltInAi {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
static cachedIsAvailable(): boolean {
|
|
47
|
-
return availability === LanguageModelAvailability.AVAILABLE
|
|
47
|
+
return availability === LanguageModelAvailability.AVAILABLE &&
|
|
48
|
+
(hasGpu || Boolean(Root.Runtime.hostConfig.devToolsAiPromptApi?.allowWithoutGpu));
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
static isGpuAvailable(): boolean {
|
|
@@ -885,50 +885,60 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
885
885
|
});
|
|
886
886
|
|
|
887
887
|
const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
|
|
888
|
-
const
|
|
889
|
-
parsedTrace.metadata.enhancedTraceVersion && parsedTrace.data.Scripts.scripts.some(s => s.content);
|
|
888
|
+
const isTraceApp = Root.Runtime.Runtime.isTraceApp();
|
|
890
889
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
},
|
|
890
|
+
this.declareFunction<{url: string}, {content: string}>('getResourceContent', {
|
|
891
|
+
description:
|
|
892
|
+
'Returns the content of the resource with the given url. Only use this for text resource types. This function is helpful for getting script contents in order to further analyze main thread activity and suggest code improvements. When analyzing the main thread activity, always call this function to get more detail. Always call this function when asked to provide specifics about what is happening in the code. Never ask permission to call this function, just do it.',
|
|
893
|
+
parameters: {
|
|
894
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
895
|
+
description: '',
|
|
896
|
+
nullable: false,
|
|
897
|
+
properties: {
|
|
898
|
+
url: {
|
|
899
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
900
|
+
description: 'The url for the resource.',
|
|
901
|
+
nullable: false,
|
|
904
902
|
},
|
|
905
903
|
},
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
904
|
+
},
|
|
905
|
+
displayInfoFromArgs: args => {
|
|
906
|
+
return {title: lockedString('Looking at resource content…'), action: `getResourceContent('${args.url}')`};
|
|
907
|
+
},
|
|
908
|
+
handler: async args => {
|
|
909
|
+
debugLog('Function call: getResourceContent');
|
|
910
|
+
|
|
911
|
+
const url = args.url as Platform.DevToolsPath.UrlString;
|
|
912
|
+
let content: string|undefined;
|
|
913
|
+
|
|
914
|
+
// First check parsedTrace.data.Scripts.
|
|
915
|
+
// Then, check ResourceTreeModel, but only when it is valid. Don't want to
|
|
916
|
+
// use if viewing a loaded trace from DevTools attached to an unrelated
|
|
917
|
+
// page.
|
|
918
|
+
const script = parsedTrace.data.Scripts.scripts.find(script => script.url === url);
|
|
919
|
+
if (script?.content !== undefined) {
|
|
920
|
+
content = script.content;
|
|
921
|
+
} else if (isFresh || isTraceApp) {
|
|
913
922
|
const resource = SDK.ResourceTreeModel.ResourceTreeModel.resourceForURL(url);
|
|
914
923
|
if (!resource) {
|
|
915
|
-
|
|
916
|
-
return {error: 'Resource not found'};
|
|
917
|
-
}
|
|
924
|
+
return {error: 'Resource not found'};
|
|
918
925
|
}
|
|
919
926
|
|
|
920
|
-
const
|
|
921
|
-
if ('error' in
|
|
922
|
-
return {error: `Could not get resource content: ${
|
|
927
|
+
const data = await resource.requestContentData();
|
|
928
|
+
if ('error' in data) {
|
|
929
|
+
return {error: `Could not get resource content: ${data.error}`};
|
|
923
930
|
}
|
|
924
931
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
return {
|
|
928
|
-
}
|
|
932
|
+
content = data.text;
|
|
933
|
+
} else {
|
|
934
|
+
return {error: 'Resource not found'};
|
|
935
|
+
}
|
|
929
936
|
|
|
930
|
-
|
|
931
|
-
|
|
937
|
+
const key = `getResourceContent(${args.url})`;
|
|
938
|
+
this.#cacheFunctionResult(focus, key, content);
|
|
939
|
+
return {result: {content}};
|
|
940
|
+
},
|
|
941
|
+
});
|
|
932
942
|
|
|
933
943
|
if (!context.external) {
|
|
934
944
|
this.declareFunction<{eventKey: string}, {success: boolean}>('selectEventByKey', {
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as Host from '../../core/host/host.js';
|
|
7
7
|
import * as Root from '../../core/root/root.js';
|
|
8
|
-
import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
|
|
9
8
|
|
|
10
9
|
import {debugLog} from './debug.js';
|
|
11
10
|
|
|
@@ -32,6 +31,20 @@ interface CachedRequest {
|
|
|
32
31
|
response: Host.AidaClient.CompletionResponse;
|
|
33
32
|
}
|
|
34
33
|
|
|
34
|
+
export interface Callbacks {
|
|
35
|
+
getSelectionHead: () => number;
|
|
36
|
+
getCompletionHint: () => string | undefined | null;
|
|
37
|
+
setAiAutoCompletion: (args: {
|
|
38
|
+
text: string,
|
|
39
|
+
from: number,
|
|
40
|
+
startTime: number,
|
|
41
|
+
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
|
|
42
|
+
clearCachedRequest: () => void,
|
|
43
|
+
rpcGlobalId?: Host.AidaClient.RpcGlobalId,
|
|
44
|
+
sampleId?: number,
|
|
45
|
+
}|null) => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
/* clang-format off */
|
|
36
49
|
const consoleAdditionalContextFileContent = `/**
|
|
37
50
|
* This file describes the execution environment of the Chrome DevTools Console.
|
|
@@ -141,24 +154,24 @@ const console = {
|
|
|
141
154
|
* the suggestion is displayed.
|
|
142
155
|
*/
|
|
143
156
|
export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
144
|
-
#editor: TextEditor.TextEditor.TextEditor;
|
|
145
157
|
#stopSequences: string[];
|
|
146
158
|
#renderingTimeout?: number;
|
|
147
159
|
#aidaRequestCache?: CachedRequest;
|
|
160
|
+
// TODO(b/445394511): Remove panel from the class
|
|
148
161
|
#panel: ContextFlavor;
|
|
162
|
+
#callbacks?: Callbacks;
|
|
149
163
|
|
|
150
164
|
readonly #sessionId: string = crypto.randomUUID();
|
|
151
165
|
readonly #aidaClient: Host.AidaClient.AidaClient;
|
|
152
166
|
readonly #serverSideLoggingEnabled: boolean;
|
|
153
167
|
|
|
154
|
-
constructor(
|
|
155
|
-
opts: AgentOptions, editor: TextEditor.TextEditor.TextEditor, panel: ContextFlavor, stopSequences?: string[]) {
|
|
168
|
+
constructor(opts: AgentOptions, panel: ContextFlavor, callbacks?: Callbacks, stopSequences?: string[]) {
|
|
156
169
|
super();
|
|
157
170
|
this.#aidaClient = opts.aidaClient;
|
|
158
171
|
this.#serverSideLoggingEnabled = opts.serverSideLoggingEnabled ?? false;
|
|
159
|
-
this.#editor = editor;
|
|
160
172
|
this.#panel = panel;
|
|
161
173
|
this.#stopSequences = stopSequences ?? [];
|
|
174
|
+
this.#callbacks = callbacks;
|
|
162
175
|
}
|
|
163
176
|
|
|
164
177
|
#debouncedRequestAidaSuggestion = Common.Debouncer.debounce(
|
|
@@ -171,8 +184,8 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
171
184
|
|
|
172
185
|
#buildRequest(
|
|
173
186
|
prefix: string, suffix: string,
|
|
174
|
-
inferenceLanguage: Host.AidaClient.AidaInferenceLanguage = Host.AidaClient.AidaInferenceLanguage.JAVASCRIPT
|
|
175
|
-
Host.AidaClient.CompletionRequest {
|
|
187
|
+
inferenceLanguage: Host.AidaClient.AidaInferenceLanguage = Host.AidaClient.AidaInferenceLanguage.JAVASCRIPT,
|
|
188
|
+
additionalFiles?: Host.AidaClient.AdditionalFile[]): Host.AidaClient.CompletionRequest {
|
|
176
189
|
const userTier = Host.AidaClient.convertToUserTierEnum(this.#userTier);
|
|
177
190
|
function validTemperature(temperature: number|undefined): number|undefined {
|
|
178
191
|
return typeof temperature === 'number' && temperature >= 0 ? temperature : undefined;
|
|
@@ -180,13 +193,15 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
180
193
|
// As a temporary fix for b/441221870 we are prepending a newline for each prefix.
|
|
181
194
|
prefix = '\n' + prefix;
|
|
182
195
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
196
|
+
let additionalContextFiles = additionalFiles ?? undefined;
|
|
197
|
+
if (!additionalContextFiles) {
|
|
198
|
+
additionalContextFiles = this.#panel === ContextFlavor.CONSOLE ? [{
|
|
199
|
+
path: 'devtools-console-context.js',
|
|
200
|
+
content: consoleAdditionalContextFileContent,
|
|
201
|
+
included_reason: Host.AidaClient.Reason.RELATED_FILE,
|
|
202
|
+
}] :
|
|
203
|
+
undefined;
|
|
204
|
+
}
|
|
190
205
|
return {
|
|
191
206
|
client: Host.AidaClient.CLIENT_NAME,
|
|
192
207
|
prefix,
|
|
@@ -203,7 +218,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
203
218
|
user_tier: userTier,
|
|
204
219
|
client_version: Root.Runtime.getChromeVersion(),
|
|
205
220
|
},
|
|
206
|
-
additional_files:
|
|
221
|
+
additional_files: additionalContextFiles,
|
|
207
222
|
};
|
|
208
223
|
}
|
|
209
224
|
|
|
@@ -239,7 +254,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
239
254
|
// `currentHint` is the portion of a standard autocomplete suggestion that the user has not yet typed.
|
|
240
255
|
// For example, if the user types `document.queryS` and the autocomplete suggests `document.querySelector`,
|
|
241
256
|
// the `currentHint` is `elector`.
|
|
242
|
-
const currentHintInMenu = this.#
|
|
257
|
+
const currentHintInMenu = this.#callbacks?.getCompletionHint();
|
|
243
258
|
// TODO(ergunsh): We should not do this check here. Instead, the AI code suggestions should be provided
|
|
244
259
|
// as it is to the view plugin. The view plugin should choose which one to use based on the completion hint
|
|
245
260
|
// and selected completion.
|
|
@@ -321,21 +336,19 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
321
336
|
} = sampleResponse;
|
|
322
337
|
const remainingDelay = Math.max(DELAY_BEFORE_SHOWING_RESPONSE_MS - (performance.now() - startTime), 0);
|
|
323
338
|
this.#renderingTimeout = window.setTimeout(() => {
|
|
324
|
-
const currentCursorPosition = this.#
|
|
339
|
+
const currentCursorPosition = this.#callbacks?.getSelectionHead();
|
|
325
340
|
if (currentCursorPosition !== cursorPositionAtRequest) {
|
|
326
341
|
this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
|
|
327
342
|
return;
|
|
328
343
|
}
|
|
329
|
-
this.#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
clearCachedRequest: this.clearCachedRequest.bind(this),
|
|
338
|
-
})
|
|
344
|
+
this.#callbacks?.setAiAutoCompletion({
|
|
345
|
+
text: suggestionText,
|
|
346
|
+
from: cursorPositionAtRequest,
|
|
347
|
+
rpcGlobalId,
|
|
348
|
+
sampleId,
|
|
349
|
+
startTime,
|
|
350
|
+
onImpression: this.registerUserImpression.bind(this),
|
|
351
|
+
clearCachedRequest: this.clearCachedRequest.bind(this),
|
|
339
352
|
});
|
|
340
353
|
|
|
341
354
|
if (fromCache) {
|
|
@@ -417,7 +430,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
417
430
|
this.#aidaRequestCache = {request, response};
|
|
418
431
|
}
|
|
419
432
|
|
|
420
|
-
|
|
433
|
+
registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number): void {
|
|
421
434
|
const seconds = Math.floor(latency / 1_000);
|
|
422
435
|
const remainingMs = latency % 1_000;
|
|
423
436
|
const nanos = Math.floor(remainingMs * 1_000_000);
|
|
@@ -469,14 +482,42 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
|
469
482
|
this.#debouncedRequestAidaSuggestion(prefix, suffix, cursorPositionAtRequest, inferenceLanguage);
|
|
470
483
|
}
|
|
471
484
|
|
|
485
|
+
async completeCode(
|
|
486
|
+
prefix: string, suffix: string, cursorPositionAtRequest: number,
|
|
487
|
+
inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage,
|
|
488
|
+
additionalFiles?: Host.AidaClient.AdditionalFile[]): Promise<{
|
|
489
|
+
response: Host.AidaClient.CompletionResponse | null,
|
|
490
|
+
fromCache: boolean,
|
|
491
|
+
}> {
|
|
492
|
+
const request = this.#buildRequest(prefix, suffix, inferenceLanguage, additionalFiles);
|
|
493
|
+
const {response, fromCache} = await this.#completeCodeCached(request);
|
|
494
|
+
|
|
495
|
+
debugLog('At cursor position', cursorPositionAtRequest, {request, response, fromCache});
|
|
496
|
+
if (!response) {
|
|
497
|
+
return {response: null, fromCache: false};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return {response, fromCache};
|
|
501
|
+
}
|
|
502
|
+
|
|
472
503
|
remove(): void {
|
|
473
504
|
if (this.#renderingTimeout) {
|
|
474
505
|
clearTimeout(this.#renderingTimeout);
|
|
475
506
|
this.#renderingTimeout = undefined;
|
|
476
507
|
}
|
|
477
|
-
this.#
|
|
478
|
-
|
|
479
|
-
|
|
508
|
+
this.#callbacks?.setAiAutoCompletion(null);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
static isAiCodeCompletionEnabled(locale: string): boolean {
|
|
512
|
+
if (!locale.startsWith('en-')) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
const aidaAvailability = Root.Runtime.hostConfig.aidaAvailability;
|
|
516
|
+
if (!aidaAvailability || aidaAvailability.blockedByGeo || aidaAvailability.blockedByAge ||
|
|
517
|
+
aidaAvailability.blockedByEnterprisePolicy) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
return Boolean(aidaAvailability.enabled && Root.Runtime.hostConfig.devToolsAiCodeCompletion?.enabled);
|
|
480
521
|
}
|
|
481
522
|
}
|
|
482
523
|
|
|
@@ -137,6 +137,20 @@ export class Importer {
|
|
|
137
137
|
async () =>
|
|
138
138
|
new TextUtils.ContentData.ContentData(contentText ?? '', isBase64, mimeType ?? '', charset ?? undefined));
|
|
139
139
|
|
|
140
|
+
if (request.mimeType === Platform.MimeType.MimeType.EVENTSTREAM && contentText) {
|
|
141
|
+
const issueTime = entry.startedDateTime.getTime() / 1000;
|
|
142
|
+
const onEvent = (eventName: string, data: string, eventId: string): void => {
|
|
143
|
+
request.addEventSourceMessage(issueTime, eventName, eventId, data);
|
|
144
|
+
};
|
|
145
|
+
const parser = new SDK.ServerSentEventProtocol.ServerSentEventsParser(onEvent, charset ?? undefined);
|
|
146
|
+
let text = contentText;
|
|
147
|
+
if (isBase64) {
|
|
148
|
+
const bytes = Common.Base64.decode(contentText);
|
|
149
|
+
text = new TextDecoder(charset ?? undefined).decode(bytes);
|
|
150
|
+
}
|
|
151
|
+
parser.addTextChunk(text);
|
|
152
|
+
}
|
|
153
|
+
|
|
140
154
|
// Timing data.
|
|
141
155
|
Importer.setupTiming(request, issueTime, entry.time, entry.timings);
|
|
142
156
|
|
|
@@ -33,7 +33,6 @@ import {SourceFrameIssuesManager} from './SourceFrameIssuesManager.js';
|
|
|
33
33
|
import {SRIMessageSignatureIssue} from './SRIMessageSignatureIssue.js';
|
|
34
34
|
import {StylesheetLoadingIssue} from './StylesheetLoadingIssue.js';
|
|
35
35
|
import {UnencodedDigestIssue} from './UnencodedDigestIssue.js';
|
|
36
|
-
import {UserReidentificationIssue} from './UserReidentificationIssue.js';
|
|
37
36
|
|
|
38
37
|
export {Events} from './IssuesManagerEvents.js';
|
|
39
38
|
|
|
@@ -145,10 +144,6 @@ const issueCodeHandlers = new Map<
|
|
|
145
144
|
Protocol.Audits.InspectorIssueCode.UnencodedDigestIssue,
|
|
146
145
|
UnencodedDigestIssue.fromInspectorIssue,
|
|
147
146
|
],
|
|
148
|
-
[
|
|
149
|
-
Protocol.Audits.InspectorIssueCode.UserReidentificationIssue,
|
|
150
|
-
UserReidentificationIssue.fromInspectorIssue,
|
|
151
|
-
],
|
|
152
147
|
]);
|
|
153
148
|
|
|
154
149
|
/**
|
|
@@ -7617,10 +7617,6 @@ export const NativeFunctions = [
|
|
|
7617
7617
|
name: "drawElementImage",
|
|
7618
7618
|
signatures: [["element","x","y","?dwidth","?dheight"]]
|
|
7619
7619
|
},
|
|
7620
|
-
{
|
|
7621
|
-
name: "setHitTestRegions",
|
|
7622
|
-
signatures: [["hitTestRegions"]]
|
|
7623
|
-
},
|
|
7624
7620
|
{
|
|
7625
7621
|
name: "Path2D",
|
|
7626
7622
|
signatures: [["?path"]]
|