chrome-devtools-frontend
Version:
Chrome DevTools UI
277 lines (251 loc) • 10.2 kB
text/typescript
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as Root from '../../core/root/root.js';
import type * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
import * as UI from '../../ui/legacy/legacy.js';
import type * as AiAssistance from './ai_assistance.js';
/*
* TODO(nvitkov): b/346933425
* Temporary string that should not be translated
* as they may change often during development.
*/
const UIStrings = {
/**
* @description The title of the AI assistance panel.
*/
aiAssistance: 'AI assistance',
/**
* @description The title of the command menu action for showing the AI assistance panel.
*/
showAiAssistance: 'Show AI assistance',
/**
* @description The setting title to enable the AI assistance via
* the settings tab.
*/
enableAiAssistance: 'Enable AI assistance',
/**
*@description Text of a tooltip to redirect to the AI assistance panel with
* the current element as context
*/
askAi: 'Ask AI',
/**
* @description Message shown to the user if the DevTools locale is not
* supported.
*/
wrongLocale: 'To use this feature, set your language preference to English in DevTools settings.',
/**
* @description Message shown to the user if the user's region is not
* supported.
*/
geoRestricted: 'This feature is unavailable in your region.',
/**
* @description Message shown to the user if the enterprise policy does
* not allow this feature.
*/
policyRestricted: 'This setting is managed by your administrator.',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/ai_assistance-meta.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
const setting = 'ai-assistance-enabled';
function isLocaleRestricted(): boolean {
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
return !devtoolsLocale.locale.startsWith('en-');
}
function isGeoRestricted(config?: Root.Runtime.HostConfig): boolean {
return config?.aidaAvailability?.blockedByGeo === true;
}
function isPolicyRestricted(config?: Root.Runtime.HostConfig): boolean {
return config?.aidaAvailability?.blockedByEnterprisePolicy === true;
}
let loadedAiAssistanceModule: (typeof AiAssistance|undefined);
async function loadAiAssistanceModule(): Promise<typeof AiAssistance> {
if (!loadedAiAssistanceModule) {
loadedAiAssistanceModule = await import('./ai_assistance.js');
}
return loadedAiAssistanceModule;
}
function isStylingAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && config?.devToolsFreestyler?.enabled) === true;
}
function isNetworkAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceNetworkAgent?.enabled)) === true;
}
function isPerformanceAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistancePerformanceAgent?.enabled)) === true;
}
function isPerformanceInsightsAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && config?.devToolsAiAssistancePerformanceAgent?.enabled &&
config?.devToolsAiAssistancePerformanceAgent.insightsEnabled) === true;
}
function isFileAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceFileAgent?.enabled)) === true;
}
function isAnyFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return isStylingAgentFeatureAvailable(config) || isNetworkAgentFeatureAvailable(config) ||
isPerformanceAgentFeatureAvailable(config) || isFileAgentFeatureAvailable(config);
}
UI.ViewManager.registerViewExtension({
location: UI.ViewManager.ViewLocationValues.DRAWER_VIEW,
id: 'freestyler',
commandPrompt: i18nLazyString(UIStrings.showAiAssistance),
title: i18nLazyString(UIStrings.aiAssistance),
order: 10,
isPreviewFeature: true,
persistence: UI.ViewManager.ViewPersistence.CLOSEABLE,
hasToolbar: false,
condition: config => isAnyFeatureAvailable(config) && !isPolicyRestricted(config),
async loadView() {
const AiAssistance = await loadAiAssistanceModule();
return await AiAssistance.AiAssistancePanel.instance();
},
});
Common.Settings.registerSettingExtension({
category: Common.Settings.SettingCategory.AI,
settingName: setting,
settingType: Common.Settings.SettingType.BOOLEAN,
title: i18nLazyString(UIStrings.enableAiAssistance),
defaultValue: false,
reloadRequired: false,
condition: isAnyFeatureAvailable,
disabledCondition: config => {
const reasons: Platform.UIString.LocalizedString[] = [];
if (isGeoRestricted(config)) {
reasons.push(i18nString(UIStrings.geoRestricted));
}
if (isPolicyRestricted(config)) {
reasons.push(i18nString(UIStrings.policyRestricted));
}
if (isLocaleRestricted()) {
reasons.push(i18nString(UIStrings.wrongLocale));
}
if (reasons.length > 0) {
return {disabled: true, reasons};
}
return {disabled: false};
},
});
UI.ActionRegistration.registerActionExtension({
actionId: 'freestyler.elements-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStylingAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'freestyler.element-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStylingAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.network-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isNetworkAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.network-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isNetworkAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.performance-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isPerformanceAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.performance-insight-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => {
return isPerformanceInsightsAgentFeatureAvailable(config) && !isPolicyRestricted(config) &&
!isGeoRestricted(config);
}
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.sources-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => isFileAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.sources-panel-context',
contextTypes() {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nLazyString(UIStrings.askAi),
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => isFileAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
// @ts-expect-error
globalThis.handleExternalRequest =
async(prompt: string, conversationType: AiAssistanceModel.ConversationType, selector?: string):
Promise<{response: string, devToolsLogs: object[]}> => {
const AiAssistance = await loadAiAssistanceModule();
const panelInstance = await AiAssistance.AiAssistancePanel.instance();
return await panelInstance.handleExternalRequest(prompt, conversationType, selector);
};