chrome-devtools-frontend 1.0.1624409 → 1.0.1624583
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/.agents/skills/foundation-test-migration/SKILL.md +1 -1
- package/front_end/core/host/AidaClient.ts +6 -5
- package/front_end/core/host/AidaClientTypes.ts +3 -1
- package/front_end/core/host/DispatchHttpRequestClient.ts +6 -3
- package/front_end/core/platform/api/HostRuntime.ts +3 -0
- package/front_end/core/platform/browser/HostRuntime.ts +10 -0
- package/front_end/core/platform/node/HostRuntime.ts +10 -0
- package/front_end/core/root/Runtime.ts +6 -5
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -3
- package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -4
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +7 -5
- package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
- package/front_end/panels/elements/StylePropertyTreeElement.ts +2 -2
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +6 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +12 -1
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +5 -1
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +5176 -5104
- package/front_end/third_party/lighthouse/locales/ar-XB.json +72 -36
- package/front_end/third_party/lighthouse/locales/ar.json +72 -36
- package/front_end/third_party/lighthouse/locales/bg.json +72 -36
- package/front_end/third_party/lighthouse/locales/ca.json +72 -36
- package/front_end/third_party/lighthouse/locales/cs.json +72 -36
- package/front_end/third_party/lighthouse/locales/da.json +74 -38
- package/front_end/third_party/lighthouse/locales/de.json +72 -36
- package/front_end/third_party/lighthouse/locales/el.json +73 -37
- package/front_end/third_party/lighthouse/locales/en-GB.json +74 -38
- package/front_end/third_party/lighthouse/locales/en-US.json +245 -17
- package/front_end/third_party/lighthouse/locales/en-XL.json +245 -17
- package/front_end/third_party/lighthouse/locales/es-419.json +72 -36
- package/front_end/third_party/lighthouse/locales/es.json +73 -37
- package/front_end/third_party/lighthouse/locales/fi.json +72 -36
- package/front_end/third_party/lighthouse/locales/fil.json +74 -38
- package/front_end/third_party/lighthouse/locales/fr.json +162 -126
- package/front_end/third_party/lighthouse/locales/he.json +74 -38
- package/front_end/third_party/lighthouse/locales/hi.json +73 -37
- package/front_end/third_party/lighthouse/locales/hr.json +72 -36
- package/front_end/third_party/lighthouse/locales/hu.json +73 -37
- package/front_end/third_party/lighthouse/locales/id.json +74 -38
- package/front_end/third_party/lighthouse/locales/it.json +72 -36
- package/front_end/third_party/lighthouse/locales/ja.json +72 -36
- package/front_end/third_party/lighthouse/locales/ko.json +72 -36
- package/front_end/third_party/lighthouse/locales/lt.json +72 -36
- package/front_end/third_party/lighthouse/locales/lv.json +72 -36
- package/front_end/third_party/lighthouse/locales/nl.json +73 -37
- package/front_end/third_party/lighthouse/locales/no.json +72 -36
- package/front_end/third_party/lighthouse/locales/pl.json +72 -36
- package/front_end/third_party/lighthouse/locales/pt-PT.json +72 -36
- package/front_end/third_party/lighthouse/locales/pt.json +74 -38
- package/front_end/third_party/lighthouse/locales/ro.json +72 -36
- package/front_end/third_party/lighthouse/locales/ru.json +72 -36
- package/front_end/third_party/lighthouse/locales/sk.json +72 -36
- package/front_end/third_party/lighthouse/locales/sl.json +72 -36
- package/front_end/third_party/lighthouse/locales/sr-Latn.json +73 -37
- package/front_end/third_party/lighthouse/locales/sr.json +73 -37
- package/front_end/third_party/lighthouse/locales/sv.json +75 -39
- package/front_end/third_party/lighthouse/locales/ta.json +73 -37
- package/front_end/third_party/lighthouse/locales/te.json +72 -36
- package/front_end/third_party/lighthouse/locales/th.json +73 -37
- package/front_end/third_party/lighthouse/locales/tr.json +72 -36
- package/front_end/third_party/lighthouse/locales/uk.json +72 -36
- package/front_end/third_party/lighthouse/locales/vi.json +74 -38
- package/front_end/third_party/lighthouse/locales/zh-HK.json +72 -36
- package/front_end/third_party/lighthouse/locales/zh-TW.json +74 -38
- package/front_end/third_party/lighthouse/locales/zh.json +75 -39
- package/front_end/third_party/lighthouse/report/bundle.js +2 -1
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +6 -2
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +4 -1
- package/front_end/ui/legacy/SuggestBox.ts +1 -0
- package/front_end/ui/legacy/TextPrompt.ts +2 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +9 -8
|
@@ -126,7 +126,7 @@ sinon.assert.calledOnceWithMatch(emulateSpy, {
|
|
|
126
126
|
### DOM Globals (`ReferenceError: FileReader is not defined`)
|
|
127
127
|
Foundation tests run in Node.js where `window`, `FileReader`, and certain DOM string encodings don't exist.
|
|
128
128
|
- **Fix**: Use isomorphic equivalents (e.g. `btoa()`, `Uint8Array`).
|
|
129
|
-
- **
|
|
129
|
+
- **Fix**: Abstract the APIs that are different between Node.js and Browser via `front_end/core/platform/api/HostRuntime.ts`.
|
|
130
130
|
|
|
131
131
|
### Initialization Order Lockups
|
|
132
132
|
If a test times out (5000ms exceeded), it is usually an unhandled promise caused by a missing singleton. Double-check the constructor of the failing manager to see which `instance()` it listens to, and ensure that dependent singleton was created *first*.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../common/common.js';
|
|
6
|
+
import * as Platform from '../platform/platform.js';
|
|
6
7
|
import * as Root from '../root/root.js';
|
|
7
8
|
|
|
8
9
|
import {
|
|
@@ -109,7 +110,7 @@ export class AidaClient {
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
static async checkAccessPreconditions(): Promise<AidaAccessPreconditions> {
|
|
112
|
-
if (!
|
|
113
|
+
if (!Platform.HostRuntime.HOST_RUNTIME.getOnLine()) {
|
|
113
114
|
return AidaAccessPreconditions.NO_INTERNET;
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -437,7 +438,7 @@ export function getClientFeatureName(feature: ClientFeature): string {
|
|
|
437
438
|
let hostConfigTrackerInstance: HostConfigTracker|undefined;
|
|
438
439
|
|
|
439
440
|
export class HostConfigTracker extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
440
|
-
#pollTimer?:
|
|
441
|
+
#pollTimer?: ReturnType<typeof setTimeout>;
|
|
441
442
|
#aidaAvailability?: AidaAccessPreconditions;
|
|
442
443
|
|
|
443
444
|
private constructor() {
|
|
@@ -456,7 +457,7 @@ export class HostConfigTracker extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
456
457
|
const isFirst = !this.hasEventListeners(eventType);
|
|
457
458
|
const eventDescriptor = super.addEventListener(eventType, listener);
|
|
458
459
|
if (isFirst) {
|
|
459
|
-
|
|
460
|
+
clearTimeout(this.#pollTimer);
|
|
460
461
|
void this.pollAidaAvailability();
|
|
461
462
|
}
|
|
462
463
|
return eventDescriptor;
|
|
@@ -466,12 +467,12 @@ export class HostConfigTracker extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
466
467
|
void {
|
|
467
468
|
super.removeEventListener(eventType, listener);
|
|
468
469
|
if (!this.hasEventListeners(eventType)) {
|
|
469
|
-
|
|
470
|
+
clearTimeout(this.#pollTimer);
|
|
470
471
|
}
|
|
471
472
|
}
|
|
472
473
|
|
|
473
474
|
async pollAidaAvailability(): Promise<void> {
|
|
474
|
-
this.#pollTimer =
|
|
475
|
+
this.#pollTimer = setTimeout(() => this.pollAidaAvailability(), 2000);
|
|
475
476
|
const currentAidaAvailability = await AidaClient.checkAccessPreconditions();
|
|
476
477
|
if (currentAidaAvailability !== this.#aidaAvailability) {
|
|
477
478
|
this.#aidaAvailability = currentAidaAvailability;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Platform from '../platform/platform.js';
|
|
6
|
+
|
|
5
7
|
export enum Role {
|
|
6
8
|
/** Provide this role when giving a function call response */
|
|
7
9
|
ROLE_UNSPECIFIED = 0,
|
|
@@ -466,7 +468,7 @@ export interface AidaChunkResponse {
|
|
|
466
468
|
}
|
|
467
469
|
|
|
468
470
|
export function debugLog(...log: unknown[]): void {
|
|
469
|
-
if (!Boolean(
|
|
471
|
+
if (!Boolean(Platform.HostRuntime.HOST_RUNTIME.getLocalStorage()?.getItem('debugAiServicesEnabled'))) {
|
|
470
472
|
return;
|
|
471
473
|
}
|
|
472
474
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Platform from '../platform/platform.js';
|
|
6
|
+
|
|
5
7
|
import {InspectorFrontendHostInstance} from './InspectorFrontendHost.js';
|
|
6
8
|
import type {DispatchHttpRequestRequest, DispatchHttpRequestResult} from './InspectorFrontendHostAPI.js';
|
|
7
9
|
|
|
@@ -56,7 +58,7 @@ export async function makeHttpRequest<R>(
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function isDebugMode(): boolean {
|
|
59
|
-
return Boolean(
|
|
61
|
+
return Boolean(Platform.HostRuntime.HOST_RUNTIME.getLocalStorage()?.getItem('debugDispatchHttpRequestEnabled'));
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
function debugLog(...log: unknown[]): void {
|
|
@@ -69,10 +71,11 @@ function debugLog(...log: unknown[]): void {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
function setDebugDispatchHttpRequestEnabled(enabled: boolean): void {
|
|
74
|
+
const localStorage = Platform.HostRuntime.HOST_RUNTIME.getLocalStorage();
|
|
72
75
|
if (enabled) {
|
|
73
|
-
localStorage
|
|
76
|
+
localStorage?.setItem('debugDispatchHttpRequestEnabled', 'true');
|
|
74
77
|
} else {
|
|
75
|
-
localStorage
|
|
78
|
+
localStorage?.removeItem('debugDispatchHttpRequestEnabled');
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -74,4 +74,14 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
|
74
74
|
return new WebWorker(url);
|
|
75
75
|
},
|
|
76
76
|
workerScope: new WebWorkerScope(),
|
|
77
|
+
getOnLine(): boolean {
|
|
78
|
+
return navigator.onLine;
|
|
79
|
+
},
|
|
80
|
+
getUserAgent(): string {
|
|
81
|
+
return navigator.userAgent;
|
|
82
|
+
},
|
|
83
|
+
getLocalStorage(): Storage |
|
|
84
|
+
undefined {
|
|
85
|
+
return 'localStorage' in globalThis ? globalThis.localStorage : undefined;
|
|
86
|
+
},
|
|
77
87
|
};
|
|
@@ -82,4 +82,14 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
|
82
82
|
return new NodeWorker(url);
|
|
83
83
|
},
|
|
84
84
|
workerScope: new NodeWorkerScope(),
|
|
85
|
+
getOnLine(): boolean {
|
|
86
|
+
return true;
|
|
87
|
+
},
|
|
88
|
+
getUserAgent(): string {
|
|
89
|
+
return 'Node.js';
|
|
90
|
+
},
|
|
91
|
+
getLocalStorage(): Storage |
|
|
92
|
+
undefined {
|
|
93
|
+
return undefined;
|
|
94
|
+
},
|
|
85
95
|
};
|
|
@@ -61,7 +61,8 @@ export function isNodeEntry(pathname: string): boolean {
|
|
|
61
61
|
|
|
62
62
|
export const getChromeVersion = (): string => {
|
|
63
63
|
const chromeRegex = /(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/;
|
|
64
|
-
const
|
|
64
|
+
const userAgent = Platform.HostRuntime.HOST_RUNTIME.getUserAgent();
|
|
65
|
+
const chromeMatch = userAgent.match(chromeRegex);
|
|
65
66
|
if (chromeMatch && chromeMatch.length > 1) {
|
|
66
67
|
return chromeMatch[1];
|
|
67
68
|
}
|
|
@@ -317,12 +318,12 @@ class ExperimentStorage {
|
|
|
317
318
|
|
|
318
319
|
constructor() {
|
|
319
320
|
try {
|
|
320
|
-
const storedExperiments =
|
|
321
|
+
const storedExperiments = Platform.HostRuntime.HOST_RUNTIME.getLocalStorage()?.getItem('experiments');
|
|
321
322
|
if (storedExperiments) {
|
|
322
323
|
this.#experiments = JSON.parse(storedExperiments);
|
|
323
324
|
}
|
|
324
|
-
} catch {
|
|
325
|
-
console.error('Failed to parse localStorage[\'experiments\']');
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error('Failed to parse localStorage[\'experiments\']: ' + err.message);
|
|
326
327
|
}
|
|
327
328
|
}
|
|
328
329
|
|
|
@@ -351,7 +352,7 @@ class ExperimentStorage {
|
|
|
351
352
|
}
|
|
352
353
|
|
|
353
354
|
#syncToLocalStorage(): void {
|
|
354
|
-
|
|
355
|
+
Platform.HostRuntime.HOST_RUNTIME.getLocalStorage()?.setItem('experiments', JSON.stringify(this.#experiments));
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
358
|
|
|
@@ -14,7 +14,6 @@ import {debugLog} from './debug.js';
|
|
|
14
14
|
interface AgentOptions {
|
|
15
15
|
aidaClient: Host.AidaClient.AidaClient;
|
|
16
16
|
serverSideLoggingEnabled?: boolean;
|
|
17
|
-
confirmSideEffectForTest?: typeof Promise.withResolvers;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
interface RequestOptions {
|
|
@@ -274,7 +273,7 @@ export class AiCodeCompletion {
|
|
|
274
273
|
|
|
275
274
|
void this.#aidaClient.registerClientEvent({
|
|
276
275
|
corresponding_aida_rpc_global_id: rpcGlobalId,
|
|
277
|
-
disable_user_content_logging:
|
|
276
|
+
disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
|
|
278
277
|
complete_code_client_event: {
|
|
279
278
|
user_impression: {
|
|
280
279
|
sample: {
|
|
@@ -296,7 +295,7 @@ export class AiCodeCompletion {
|
|
|
296
295
|
registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
|
|
297
296
|
void this.#aidaClient.registerClientEvent({
|
|
298
297
|
corresponding_aida_rpc_global_id: rpcGlobalId,
|
|
299
|
-
disable_user_content_logging:
|
|
298
|
+
disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
|
|
300
299
|
complete_code_client_event: {
|
|
301
300
|
user_acceptance: {
|
|
302
301
|
sample: {
|
|
@@ -39,7 +39,6 @@ The console has direct access to the inspected page's \`window\` and \`document\
|
|
|
39
39
|
interface Options {
|
|
40
40
|
aidaClient: Host.AidaClient.AidaClient;
|
|
41
41
|
serverSideLoggingEnabled?: boolean;
|
|
42
|
-
confirmSideEffectForTest?: typeof Promise.withResolvers;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
interface RequestOptions {
|
|
@@ -124,7 +123,7 @@ export class AiCodeGeneration {
|
|
|
124
123
|
|
|
125
124
|
void this.#aidaClient.registerClientEvent({
|
|
126
125
|
corresponding_aida_rpc_global_id: rpcGlobalId,
|
|
127
|
-
disable_user_content_logging:
|
|
126
|
+
disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
|
|
128
127
|
generate_code_client_event: {
|
|
129
128
|
user_impression: {
|
|
130
129
|
sample: {
|
|
@@ -146,7 +145,7 @@ export class AiCodeGeneration {
|
|
|
146
145
|
registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
|
|
147
146
|
void this.#aidaClient.registerClientEvent({
|
|
148
147
|
corresponding_aida_rpc_global_id: rpcGlobalId,
|
|
149
|
-
disable_user_content_logging:
|
|
148
|
+
disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
|
|
150
149
|
generate_code_client_event: {
|
|
151
150
|
user_acceptance: {
|
|
152
151
|
sample: {
|
|
@@ -531,7 +531,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
531
531
|
let walkthroughIsForLastMessage = false;
|
|
532
532
|
if(input.state === ViewState.CHAT_VIEW) {
|
|
533
533
|
const lastMessage = input.props.messages.at(-1);
|
|
534
|
-
if(lastMessage && input.props.walkthrough.activeSidebarMessage === lastMessage) {
|
|
534
|
+
if(lastMessage && input.props.walkthrough.activeSidebarMessage?.id === lastMessage.id) {
|
|
535
535
|
walkthroughIsForLastMessage = true;
|
|
536
536
|
}
|
|
537
537
|
}
|
|
@@ -879,7 +879,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
879
879
|
}
|
|
880
880
|
|
|
881
881
|
#openWalkthrough(message: ModelChatMessage): void {
|
|
882
|
-
if (!this.#walkthrough.inlineExpandedMessages.
|
|
882
|
+
if (!this.#walkthrough.inlineExpandedMessages.some(m => m.id === message.id)) {
|
|
883
883
|
this.#walkthrough.inlineExpandedMessages.push(message);
|
|
884
884
|
}
|
|
885
885
|
this.#walkthrough.activeSidebarMessage = message;
|
|
@@ -905,7 +905,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
905
905
|
}
|
|
906
906
|
|
|
907
907
|
// If we are closing a walkthrough, remove it from the list of expanded messages.
|
|
908
|
-
this.#walkthrough.inlineExpandedMessages =
|
|
908
|
+
this.#walkthrough.inlineExpandedMessages =
|
|
909
|
+
this.#walkthrough.inlineExpandedMessages.filter(m => m.id !== message.id);
|
|
909
910
|
|
|
910
911
|
if (this.#walkthrough.isInlined) {
|
|
911
912
|
// In Narrow mode, the global expanded state tracks if at least one walkthrough is open.
|
|
@@ -913,7 +914,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
913
914
|
// If the message we just closed was the active one, we pick a new active message
|
|
914
915
|
// from the remaining open ones (if any). This ensures that if the user
|
|
915
916
|
// re-opens the sidebar later, it shows the most recently opened walkthrough.
|
|
916
|
-
if (this.#walkthrough.activeSidebarMessage === message) {
|
|
917
|
+
if (this.#walkthrough.activeSidebarMessage?.id === message.id) {
|
|
917
918
|
this.#walkthrough.activeSidebarMessage = this.#walkthrough.inlineExpandedMessages.at(-1) ?? null;
|
|
918
919
|
}
|
|
919
920
|
} else {
|
|
@@ -1857,6 +1858,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1857
1858
|
let systemMessage: ModelChatMessage = {
|
|
1858
1859
|
entity: ChatMessageEntity.MODEL,
|
|
1859
1860
|
parts: [],
|
|
1861
|
+
id: crypto.randomUUID(),
|
|
1860
1862
|
};
|
|
1861
1863
|
let step: Step = {isLoading: true};
|
|
1862
1864
|
|
|
@@ -1885,10 +1887,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1885
1887
|
entity: ChatMessageEntity.USER,
|
|
1886
1888
|
text: data.query,
|
|
1887
1889
|
imageInput: data.imageInput,
|
|
1890
|
+
id: crypto.randomUUID(),
|
|
1888
1891
|
});
|
|
1889
1892
|
systemMessage = {
|
|
1890
1893
|
entity: ChatMessageEntity.MODEL,
|
|
1891
1894
|
parts: [],
|
|
1895
|
+
id: crypto.randomUUID(),
|
|
1892
1896
|
};
|
|
1893
1897
|
this.#messages.push(systemMessage);
|
|
1894
1898
|
// If the walkthrough is currently expanded in the sidebar, we want to
|
|
@@ -435,6 +435,7 @@ export interface UserChatMessage {
|
|
|
435
435
|
entity: ChatMessageEntity.USER;
|
|
436
436
|
text: string;
|
|
437
437
|
imageInput?: Host.AidaClient.Part;
|
|
438
|
+
id: string;
|
|
438
439
|
}
|
|
439
440
|
|
|
440
441
|
export interface ModelChatMessage {
|
|
@@ -442,6 +443,7 @@ export interface ModelChatMessage {
|
|
|
442
443
|
parts: ModelMessagePart[];
|
|
443
444
|
error?: AiAssistanceModel.AiAgent.ErrorType;
|
|
444
445
|
rpcId?: Host.AidaClient.RpcGlobalId;
|
|
446
|
+
id: string;
|
|
445
447
|
}
|
|
446
448
|
|
|
447
449
|
export type Message = UserChatMessage|ModelChatMessage;
|
|
@@ -740,7 +742,7 @@ function renderWalkthroughSidebarButton(
|
|
|
740
742
|
}
|
|
741
743
|
|
|
742
744
|
const hasOneStepWithWidget = steps.some(step => step.widgets?.length);
|
|
743
|
-
const isExpanded = walkthrough.isExpanded && input.message === input.walkthrough.activeSidebarMessage;
|
|
745
|
+
const isExpanded = walkthrough.isExpanded && input.message.id === input.walkthrough.activeSidebarMessage?.id;
|
|
744
746
|
const title = isExpanded ? walkthroughCloseTitle({hasWidgets: hasOneStepWithWidget}) : walkthroughTitle({
|
|
745
747
|
isLoading: input.isLoading,
|
|
746
748
|
hasWidgets: hasOneStepWithWidget,
|
|
@@ -781,7 +783,7 @@ function renderWalkthroughSidebarButton(
|
|
|
781
783
|
.jslogContext=${walkthrough.isExpanded ? 'ai-hide-walkthrough-sidebar' : 'ai-show-walkthrough-sidebar'}
|
|
782
784
|
data-show-walkthrough
|
|
783
785
|
@click=${() => {
|
|
784
|
-
if(walkthrough.activeSidebarMessage === input.message && walkthrough.isExpanded) {
|
|
786
|
+
if(walkthrough.activeSidebarMessage?.id === input.message.id && walkthrough.isExpanded) {
|
|
785
787
|
walkthrough.onToggle(false, message as ModelChatMessage);
|
|
786
788
|
} else {
|
|
787
789
|
// Can't just toggle the visibility here; we need to ensure we
|
|
@@ -816,8 +818,8 @@ function renderWalkthroughUI(input: ChatMessageViewInput, steps: Step[]): Lit.Li
|
|
|
816
818
|
// open and it is specifically targeting this message. This is necessary
|
|
817
819
|
// because the walkthrough state is shared across all messages in the chat.
|
|
818
820
|
const isExpanded = input.walkthrough.isInlined ?
|
|
819
|
-
input.walkthrough.inlineExpandedMessages.
|
|
820
|
-
(input.walkthrough.isExpanded && input.walkthrough.activeSidebarMessage === input.message);
|
|
821
|
+
input.walkthrough.inlineExpandedMessages.some(m => m.id === input.message.id) :
|
|
822
|
+
(input.walkthrough.isExpanded && input.walkthrough.activeSidebarMessage?.id === input.message.id);
|
|
821
823
|
|
|
822
824
|
// clang-format off
|
|
823
825
|
const walkthroughInline = input.walkthrough.isInlined ? html`
|
|
@@ -1775,7 +1777,7 @@ function renderActions(input: ChatMessageViewInput, output: ViewOutput): Lit.Lit
|
|
|
1775
1777
|
}
|
|
1776
1778
|
|
|
1777
1779
|
export class ChatMessage extends UI.Widget.Widget {
|
|
1778
|
-
message: Message = {entity: ChatMessageEntity.USER, text: ''};
|
|
1780
|
+
message: Message = {entity: ChatMessageEntity.USER, text: '', id: ''};
|
|
1779
1781
|
isLoading = false;
|
|
1780
1782
|
isReadOnly = false;
|
|
1781
1783
|
prompt = '';
|
|
@@ -155,7 +155,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
155
155
|
<main @scroll=${input.handleScroll} ${ref(element => { output.mainElement = element as HTMLElement; } )}>
|
|
156
156
|
${input.messages.length > 0 ? html`
|
|
157
157
|
<div class="messages-container" ${ref(input.handleMessageContainerRef)}>
|
|
158
|
-
${repeat(input.messages, (message, index) => {
|
|
158
|
+
${repeat(input.messages, message => message.id, (message, index) => {
|
|
159
159
|
const prevMessage = index > 0 ? input.messages[index - 1] : null;
|
|
160
160
|
const prompt = (message.entity === ChatMessageEntity.MODEL && prevMessage?.entity === ChatMessageEntity.USER) ?
|
|
161
161
|
prevMessage.text :
|
|
@@ -169,7 +169,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
169
169
|
isLastMessage: index === input.messages.length - 1,
|
|
170
170
|
isFirstMessage: index === 0,
|
|
171
171
|
prompt,
|
|
172
|
-
shouldShowCSSChangeSummary: message === cssChangeSummaryMessage,
|
|
172
|
+
shouldShowCSSChangeSummary: message.id === cssChangeSummaryMessage?.id,
|
|
173
173
|
onSuggestionClick: input.handleSuggestionClick,
|
|
174
174
|
onFeedbackSubmit: input.onFeedbackSubmit,
|
|
175
175
|
onCopyResponseClick: input.onCopyResponseClick,
|
|
@@ -3637,12 +3637,12 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
3637
3637
|
}
|
|
3638
3638
|
const isEditingName = UI.UIUtils.isBeingEdited(this.nameElement);
|
|
3639
3639
|
if (isEditingName) {
|
|
3640
|
-
this.prompt.applySuggestion({text: activeAiSuggestion.name}, true);
|
|
3640
|
+
this.prompt.applySuggestion({text: activeAiSuggestion.name, disableAcceptSuggestionOnStopCharacters: true}, true);
|
|
3641
3641
|
this.#showGhostTextInValue(activeAiSuggestion.value);
|
|
3642
3642
|
} else {
|
|
3643
3643
|
// Only has ghost text for one field - name part or value part
|
|
3644
3644
|
const currentSuggestedText = isEditingName ? activeAiSuggestion.name : activeAiSuggestion.value;
|
|
3645
|
-
this.prompt.applySuggestion({text: currentSuggestedText}, true);
|
|
3645
|
+
this.prompt.applySuggestion({text: currentSuggestedText, disableAcceptSuggestionOnStopCharacters: true}, true);
|
|
3646
3646
|
}
|
|
3647
3647
|
}
|
|
3648
3648
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as Host from '../../core/host/host.js';
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
|
+
import * as Root from '../../core/root/root.js';
|
|
8
9
|
import type * as SDK from '../../core/sdk/sdk.js';
|
|
9
10
|
import * as AiCodeCompletion from '../../models/ai_code_completion/ai_code_completion.js';
|
|
10
11
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
@@ -61,7 +62,11 @@ export class StylesAiCodeCompletionProvider {
|
|
|
61
62
|
stopSequences.push(...this.#aiCodeCompletionConfig.completionContext.stopSequences);
|
|
62
63
|
}
|
|
63
64
|
this.#aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
|
|
64
|
-
{
|
|
65
|
+
{
|
|
66
|
+
aidaClient: this.#aidaClient,
|
|
67
|
+
serverSideLoggingEnabled: !Root.Runtime.hostConfig.aidaAvailability?.disallowLogging
|
|
68
|
+
},
|
|
69
|
+
this.#aiCodeCompletionConfig.panel, undefined, stopSequences);
|
|
65
70
|
this.#aiCodeCompletionConfig.onFeatureEnabled();
|
|
66
71
|
}
|
|
67
72
|
|
|
@@ -135,10 +135,16 @@ const UIStrings = {
|
|
|
135
135
|
* @description Tooltip text for the link in the sidebar pane layer separators that reveals the layer in the layer tree view.
|
|
136
136
|
*/
|
|
137
137
|
clickToRevealLayer: 'Click to reveal layer in layer tree',
|
|
138
|
+
/**
|
|
139
|
+
* @description Text to announce that the AI suggestion was accepted.
|
|
140
|
+
* @example {color: blue;} PH1
|
|
141
|
+
*/
|
|
142
|
+
aiSuggestionAccepted: '{PH1} Suggestion accepted.',
|
|
138
143
|
} as const;
|
|
139
144
|
|
|
140
145
|
const str_ = i18n.i18n.registerUIStrings('panels/elements/StylesSidebarPane.ts', UIStrings);
|
|
141
146
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
147
|
+
const lockedString = i18n.i18n.lockedString;
|
|
142
148
|
|
|
143
149
|
// Number of ms elapsed with no keypresses to determine is the input is finished, to announce results
|
|
144
150
|
const FILTER_IDLE_PERIOD = 500;
|
|
@@ -2289,6 +2295,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2289
2295
|
if (args.rpcGlobalId) {
|
|
2290
2296
|
args.onImpression(args.rpcGlobalId, latency, args.sampleId);
|
|
2291
2297
|
}
|
|
2298
|
+
UI.ARIAUtils.LiveAnnouncer.status(lockedString(styleText));
|
|
2292
2299
|
}
|
|
2293
2300
|
|
|
2294
2301
|
#getAiSuggestedProperties(suggestionText: string): ActiveAiSuggestionProperty[] {
|
|
@@ -2369,7 +2376,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2369
2376
|
// Explicitly set the query range as it is cleared during `acceptAutoComplete`
|
|
2370
2377
|
this.queryRange = new TextUtils.TextRange.TextRange(0, 0, 0, textAfterAccept.length);
|
|
2371
2378
|
// Re-apply the ghost text for the remainder
|
|
2372
|
-
this.applySuggestion({text: suggestionForCurrentPrompt}, true);
|
|
2379
|
+
this.applySuggestion({text: suggestionForCurrentPrompt, disableAcceptSuggestionOnStopCharacters: true}, true);
|
|
2373
2380
|
}
|
|
2374
2381
|
return true;
|
|
2375
2382
|
}
|
|
@@ -2384,12 +2391,16 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2384
2391
|
}
|
|
2385
2392
|
|
|
2386
2393
|
async commitAiSuggestion(): Promise<void> {
|
|
2394
|
+
const suggestionText = this.treeElement.section().activeAiSuggestion?.text;
|
|
2387
2395
|
await this.treeElement.section().commitActiveAiSuggestion();
|
|
2388
2396
|
if (this.activeAiSuggestionInfo) {
|
|
2389
2397
|
this.aiCodeCompletionProvider?.onSuggestionAccepted(
|
|
2390
2398
|
this.activeAiSuggestionInfo.citations, this.activeAiSuggestionInfo.rpcGlobalId,
|
|
2391
2399
|
this.activeAiSuggestionInfo.sampleId);
|
|
2392
2400
|
}
|
|
2401
|
+
if (suggestionText) {
|
|
2402
|
+
UI.ARIAUtils.LiveAnnouncer.status(i18nString(UIStrings.aiSuggestionAccepted, {PH1: suggestionText}));
|
|
2403
|
+
}
|
|
2393
2404
|
// Clear state and return
|
|
2394
2405
|
this.setAiAutoCompletion(null);
|
|
2395
2406
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Name: Lighthouse
|
|
2
2
|
Short Name: lighthouse
|
|
3
|
-
Version: 13.
|
|
4
|
-
Revision:
|
|
3
|
+
Version: 13.2.0
|
|
4
|
+
Revision: a160d341f363acf2d99314214a6e0de7d0fead1f
|
|
5
5
|
Update Mechanism: Manual
|
|
6
6
|
URL: https://github.com/GoogleChrome/lighthouse
|
|
7
7
|
License: Apache-2.0
|