chrome-devtools-frontend 1.0.1541552 → 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 +1 -0
- package/front_end/core/common/Settings.ts +38 -15
- 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 +6 -3
- package/front_end/foundation/Universe.ts +2 -10
- package/front_end/generated/SupportedCSSProperties.js +42 -42
- 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/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/third_party/chromium/README.chromium +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/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/visual_logging/KnownContextValues.ts +11 -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
package/docs/get_the_code.md
CHANGED
|
@@ -368,6 +368,15 @@ out/Default/chrome --custom-devtools-frontend=file://$(realpath out/Default/gen/
|
|
|
368
368
|
afterwards, which can be quite a bit faster than building and linking the full
|
|
369
369
|
Chromium binary.
|
|
370
370
|
|
|
371
|
+
Alternatively you can use `npm start` from the DevTools sub folder (`third_party/devtools-frontend/src/`) with the browser set to `chromium`.
|
|
372
|
+
This will tell the command that you are in a Chromium checkout and try to find the correct browser executable path to resolve.
|
|
373
|
+
Or alternately you can use a `.env` file, see [set up here](#using-a-env-file-for-default-script-options).
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
cd third_party/devtools-frontend/src/
|
|
377
|
+
npm start -- --browser=chromium
|
|
378
|
+
```
|
|
379
|
+
|
|
371
380
|
### Testing
|
|
372
381
|
|
|
373
382
|
To run the test suite, use `npm test` from within the DevTools front-end folder:
|
package/front_end/Tests.js
CHANGED
|
@@ -10,7 +10,6 @@ import type {EventDescriptor, EventTargetEvent, GenericEvents} from './EventTarg
|
|
|
10
10
|
import {ObjectWrapper} from './Object.js';
|
|
11
11
|
import {
|
|
12
12
|
getLocalizedSettingsCategory,
|
|
13
|
-
getRegisteredSettings as getRegisteredSettingsInternal,
|
|
14
13
|
type LearnMore,
|
|
15
14
|
maybeRemoveSettingExtension,
|
|
16
15
|
type RegExpSettingItem,
|
|
@@ -25,7 +24,21 @@ import {
|
|
|
25
24
|
|
|
26
25
|
let settingsInstance: Settings|undefined;
|
|
27
26
|
|
|
27
|
+
export interface SettingsCreationOptions {
|
|
28
|
+
syncedStorage: SettingsStorage;
|
|
29
|
+
globalStorage: SettingsStorage;
|
|
30
|
+
localStorage: SettingsStorage;
|
|
31
|
+
settingRegistrations: SettingRegistration[];
|
|
32
|
+
logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
|
|
33
|
+
runSettingsMigration?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
export class Settings {
|
|
37
|
+
readonly syncedStorage: SettingsStorage;
|
|
38
|
+
readonly globalStorage: SettingsStorage;
|
|
39
|
+
readonly localStorage: SettingsStorage;
|
|
40
|
+
|
|
41
|
+
readonly #settingRegistrations: SettingRegistration[];
|
|
29
42
|
readonly #sessionStorage = new SettingsStorage({});
|
|
30
43
|
settingNameSet = new Set<string>();
|
|
31
44
|
orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
|
|
@@ -34,16 +47,16 @@ export class Settings {
|
|
|
34
47
|
readonly moduleSettings = new Map<string, Setting<unknown>>();
|
|
35
48
|
#logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
constructor(
|
|
51
|
+
{syncedStorage, globalStorage, localStorage, settingRegistrations, logSettingAccess, runSettingsMigration}:
|
|
52
|
+
SettingsCreationOptions) {
|
|
53
|
+
this.syncedStorage = syncedStorage;
|
|
54
|
+
this.globalStorage = globalStorage;
|
|
55
|
+
this.localStorage = localStorage;
|
|
56
|
+
this.#settingRegistrations = settingRegistrations;
|
|
44
57
|
this.#logSettingAccess = logSettingAccess;
|
|
45
58
|
|
|
46
|
-
for (const registration of this
|
|
59
|
+
for (const registration of this.#settingRegistrations) {
|
|
47
60
|
const {settingName, defaultValue, storageType} = registration;
|
|
48
61
|
const isRegex = registration.settingType === SettingType.REGEX;
|
|
49
62
|
|
|
@@ -68,7 +81,7 @@ export class Settings {
|
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
getRegisteredSettings(): SettingRegistration[] {
|
|
71
|
-
return
|
|
84
|
+
return this.#settingRegistrations;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
static hasInstance(): boolean {
|
|
@@ -80,17 +93,27 @@ export class Settings {
|
|
|
80
93
|
syncedStorage: SettingsStorage|null,
|
|
81
94
|
globalStorage: SettingsStorage|null,
|
|
82
95
|
localStorage: SettingsStorage|null,
|
|
96
|
+
settingRegistrations: SettingRegistration[]|null,
|
|
83
97
|
logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>,
|
|
84
98
|
runSettingsMigration?: boolean,
|
|
85
|
-
} = {forceNew: null, syncedStorage: null, globalStorage: null, localStorage: null}):
|
|
86
|
-
|
|
99
|
+
} = {forceNew: null, syncedStorage: null, globalStorage: null, localStorage: null, settingRegistrations: null}):
|
|
100
|
+
Settings {
|
|
101
|
+
const {
|
|
102
|
+
forceNew,
|
|
103
|
+
syncedStorage,
|
|
104
|
+
globalStorage,
|
|
105
|
+
localStorage,
|
|
106
|
+
settingRegistrations,
|
|
107
|
+
logSettingAccess,
|
|
108
|
+
runSettingsMigration
|
|
109
|
+
} = opts;
|
|
87
110
|
if (!settingsInstance || forceNew) {
|
|
88
|
-
if (!syncedStorage || !globalStorage || !localStorage) {
|
|
111
|
+
if (!syncedStorage || !globalStorage || !localStorage || !settingRegistrations) {
|
|
89
112
|
throw new Error(`Unable to create settings: global and local storage must be provided: ${new Error().stack}`);
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
settingsInstance =
|
|
93
|
-
|
|
115
|
+
settingsInstance = new Settings(
|
|
116
|
+
{syncedStorage, globalStorage, localStorage, settingRegistrations, logSettingAccess, runSettingsMigration});
|
|
94
117
|
}
|
|
95
118
|
|
|
96
119
|
return settingsInstance;
|
|
@@ -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;
|
|
@@ -168,9 +168,12 @@ export class MainImpl {
|
|
|
168
168
|
Object.assign(Root.Runtime.hostConfig, config);
|
|
169
169
|
|
|
170
170
|
const creationOptions: Foundation.Universe.CreationOptions = {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
settingsCreationOptions: {
|
|
172
|
+
...this.createSettingsStorage(prefs),
|
|
173
|
+
settingRegistrations: Common.SettingRegistration.getRegisteredSettings(),
|
|
174
|
+
logSettingAccess: VisualLogging.logSettingAccess,
|
|
175
|
+
runSettingsMigration: !Host.InspectorFrontendHost.isUnderTest(),
|
|
176
|
+
},
|
|
174
177
|
};
|
|
175
178
|
new Foundation.Universe.Universe(creationOptions);
|
|
176
179
|
|
|
@@ -6,11 +6,7 @@ import * as Common from '../core/common/common.js';
|
|
|
6
6
|
|
|
7
7
|
export interface CreationOptions {
|
|
8
8
|
// Settings things
|
|
9
|
-
|
|
10
|
-
globalStorage: Common.Settings.SettingsStorage;
|
|
11
|
-
localStorage: Common.Settings.SettingsStorage;
|
|
12
|
-
logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
|
|
13
|
-
runSettingsMigration?: boolean;
|
|
9
|
+
settingsCreationOptions: Common.Settings.SettingsCreationOptions;
|
|
14
10
|
}
|
|
15
11
|
|
|
16
12
|
export class Universe {
|
|
@@ -19,11 +15,7 @@ export class Universe {
|
|
|
19
15
|
// For now the global is fine as we don't anticipate the MCP server to change settings.
|
|
20
16
|
Common.Settings.Settings.instance({
|
|
21
17
|
forceNew: true,
|
|
22
|
-
|
|
23
|
-
globalStorage: options.globalStorage,
|
|
24
|
-
localStorage: options.localStorage,
|
|
25
|
-
logSettingAccess: options.logSettingAccess,
|
|
26
|
-
runSettingsMigration: options.runSettingsMigration,
|
|
18
|
+
...options.settingsCreationOptions,
|
|
27
19
|
});
|
|
28
20
|
}
|
|
29
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": [
|
|
@@ -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"]]
|
|
@@ -44,6 +44,7 @@ type GeneratedFileSizes = {
|
|
|
44
44
|
}|{files: Record<string, number>, unmappedBytes: number, totalBytes: number};
|
|
45
45
|
|
|
46
46
|
let scriptById = new Map<string, Script>();
|
|
47
|
+
let frameIdByIsolate = new Map<string, string>();
|
|
47
48
|
|
|
48
49
|
export function deps(): HandlerName[] {
|
|
49
50
|
return ['Meta', 'NetworkRequests'];
|
|
@@ -51,6 +52,7 @@ export function deps(): HandlerName[] {
|
|
|
51
52
|
|
|
52
53
|
export function reset(): void {
|
|
53
54
|
scriptById = new Map();
|
|
55
|
+
frameIdByIsolate = new Map();
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export function handleEvent(event: Types.Events.Event): void {
|
|
@@ -73,6 +75,9 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
73
75
|
if (Types.Events.isRundownScript(event)) {
|
|
74
76
|
const {isolate, scriptId, url, sourceUrl, sourceMapUrl, sourceMapUrlElided} = event.args.data;
|
|
75
77
|
const script = getOrMakeScript(isolate, scriptId);
|
|
78
|
+
if (!script.frame) {
|
|
79
|
+
script.frame = frameIdByIsolate.get(String(isolate)) ?? '';
|
|
80
|
+
}
|
|
76
81
|
script.url = url;
|
|
77
82
|
script.ts = event.ts;
|
|
78
83
|
if (sourceUrl) {
|
|
@@ -105,6 +110,27 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
105
110
|
script.content = (script.content ?? '') + sourceText;
|
|
106
111
|
return;
|
|
107
112
|
}
|
|
113
|
+
|
|
114
|
+
// Setup frameIdByIsolate, which is used only in the case that we are missing
|
|
115
|
+
// rundown events for a script. We won't get a frame association from the rundown
|
|
116
|
+
// events if the recording started only after the script was first compiled. In
|
|
117
|
+
// that scenario, derive the frame via the isolate / FunctionCall events.
|
|
118
|
+
// TODO: ideally, we put the frame on ScriptCatchup event. So much easier. This approach has some
|
|
119
|
+
// issues.
|
|
120
|
+
if (Types.Events.isFunctionCall(event) && event.args.data?.isolate && event.args.data.frame) {
|
|
121
|
+
const {isolate, frame} = event.args.data;
|
|
122
|
+
const existingValue = frameIdByIsolate.get(isolate);
|
|
123
|
+
if (existingValue !== frame) {
|
|
124
|
+
frameIdByIsolate.set(isolate, frame);
|
|
125
|
+
|
|
126
|
+
// Update the scripts we discovered but without knowing their frame.
|
|
127
|
+
for (const script of scriptById.values()) {
|
|
128
|
+
if (!script.frame && script.isolate === isolate) {
|
|
129
|
+
script.frame = frame;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
108
134
|
}
|
|
109
135
|
|
|
110
136
|
function findFrame(meta: MetaHandlerData, frameId: string): Types.Events.TraceFrame|null {
|