Skip to content

Commit c4b4c9e

Browse files
wolfibDevtools-frontend LUCI CQ
authored andcommitted
Add global debugProblem method for calling AI assistance
Bug: 416138589 Change-Id: I2426a50569117f994e4bf8725b6f8a54bbdbcd89 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6520239 Commit-Queue: Alex Rudenko <alexrudenko@chromium.org> Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
1 parent ff9bf3f commit c4b4c9e

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

front_end/panels/ai_assistance/AiAssistancePanel.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,93 @@ describeWithMockConnection('AI Assistance Panel', () => {
13931393
assert.isUndefined((await view.nextInput).imageInput);
13941394
});
13951395
});
1396+
1397+
describe('debugProblem', () => {
1398+
const explanation = 'I need more information';
1399+
const notAvailable =
1400+
'For AI features to be available, you need to log into Chrome and enable AI assistance in DevTools settings';
1401+
1402+
beforeEach(() => {
1403+
Common.Settings.moduleSetting('ai-assistance-enabled').set(true);
1404+
updateHostConfig({
1405+
devToolsFreestyler: {
1406+
enabled: true,
1407+
},
1408+
});
1409+
});
1410+
1411+
it('can be blocked by a setting', async () => {
1412+
Common.Settings.moduleSetting('ai-assistance-enabled').set(false);
1413+
const {panel} = await createAiAssistancePanel({
1414+
aidaClient: mockAidaClient([[{explanation}]]),
1415+
});
1416+
try {
1417+
await panel.debugProblem('Please help me debug this problem');
1418+
assert.fail('Expected `debugProblem` to throw');
1419+
} catch (err) {
1420+
assert.strictEqual(err.message, notAvailable);
1421+
}
1422+
});
1423+
1424+
it('can be blocked by feature availability', async () => {
1425+
const {panel} = await createAiAssistancePanel({
1426+
aidaClient: mockAidaClient([[{explanation}]]),
1427+
aidaAvailability: Host.AidaClient.AidaAccessPreconditions.SYNC_IS_PAUSED,
1428+
});
1429+
try {
1430+
await panel.debugProblem('Please help me debug this problem');
1431+
assert.fail('Expected `debugProblem` to throw');
1432+
} catch (err) {
1433+
assert.strictEqual(err.message, notAvailable);
1434+
}
1435+
});
1436+
1437+
it('can be blocked by user age', async () => {
1438+
updateHostConfig({
1439+
aidaAvailability: {
1440+
blockedByAge: true,
1441+
},
1442+
devToolsFreestyler: {
1443+
enabled: true,
1444+
},
1445+
});
1446+
const {panel} = await createAiAssistancePanel({
1447+
aidaClient: mockAidaClient([[{explanation}]]),
1448+
});
1449+
try {
1450+
await panel.debugProblem('Please help me debug this problem');
1451+
assert.fail('Expected `debugProblem` to throw');
1452+
} catch (err) {
1453+
assert.strictEqual(err.message, notAvailable);
1454+
}
1455+
});
1456+
1457+
it('returns an explanation', async () => {
1458+
const {panel} = await createAiAssistancePanel({
1459+
aidaClient: mockAidaClient([[{explanation}]]),
1460+
});
1461+
const response = await panel.debugProblem('Please help me debug this problem');
1462+
assert.strictEqual(response, explanation);
1463+
});
1464+
1465+
it('throws an error if no answer could be generated', async () => {
1466+
const {panel} = await createAiAssistancePanel({
1467+
aidaClient: mockAidaClient([
1468+
[{
1469+
explanation: `ACTION
1470+
$0.style.backgroundColor = 'red'
1471+
STOP`,
1472+
}],
1473+
])
1474+
});
1475+
try {
1476+
await panel.debugProblem('Please help me debug this problem');
1477+
assert.fail('Expected `debugProblem` to throw');
1478+
} catch (err) {
1479+
assert.strictEqual(err.message, 'Something went wrong. No answer was generated.');
1480+
}
1481+
});
1482+
});
13961483
});
13971484

13981485
describeWithEnvironment('AiAssistancePanel.ActionDelegate', () => {

front_end/panels/ai_assistance/AiAssistancePanel.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,43 @@ export class AiAssistancePanel extends UI.Panel.Panel {
13101310
return context;
13111311
}
13121312

1313+
// Called by MCP server via Puppeteer
1314+
// TODO(http://b/416460908) Make this generic and select the agent based on an input parameter
1315+
async debugProblem(prompt: string): Promise<string> {
1316+
const aiAssistanceSetting = this.#aiAssistanceEnabledSetting?.getIfNotDisabled();
1317+
const isBlockedByAge = Root.Runtime.hostConfig.aidaAvailability?.blockedByAge === true;
1318+
const isAidaAvailable = this.#aidaAvailability === Host.AidaClient.AidaAccessPreconditions.AVAILABLE;
1319+
if (!aiAssistanceSetting || isBlockedByAge || !isAidaAvailable) {
1320+
throw new Error(
1321+
'For AI features to be available, you need to log into Chrome and enable AI assistance in DevTools settings');
1322+
}
1323+
1324+
const stylingAgent = this.#createAgent(AiAssistanceModel.ConversationType.STYLING);
1325+
// Cancel any previous in-flight conversation.
1326+
this.#cancel();
1327+
const runner = stylingAgent.run(
1328+
prompt,
1329+
{
1330+
signal: this.#runAbortController.signal,
1331+
// TODO(crbug.com/416134018) provide context via MCP instead of using the currently selected element
1332+
selected: this.#getConversationContext(),
1333+
},
1334+
);
1335+
for await (const data of runner) {
1336+
if (data.type === AiAssistanceModel.ResponseType.SIDE_EFFECT) {
1337+
data.confirm(true);
1338+
}
1339+
if (data.type === AiAssistanceModel.ResponseType.ANSWER && data.complete) {
1340+
await this.#changeManager.stashChanges();
1341+
this.#changeManager.dropStashedChanges();
1342+
return data.text;
1343+
}
1344+
}
1345+
await this.#changeManager.stashChanges();
1346+
this.#changeManager.dropStashedChanges();
1347+
throw new Error('Something went wrong. No answer was generated.');
1348+
}
1349+
13131350
async #startConversation(
13141351
text: string, imageInput?: Host.AidaClient.Part,
13151352
multimodalInputType?: AiAssistanceModel.MultimodalInputType): Promise<void> {

front_end/panels/ai_assistance/ai_assistance-meta.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,12 @@ UI.ActionRegistration.registerActionExtension({
263263
},
264264
condition: config => isFileAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
265265
});
266+
267+
// Called by MCP server via Puppeteer
268+
// TODO(http://b/416460908) Make this generic and select the agent based on an input parameter
269+
// @ts-expect-error
270+
globalThis.debugProblem = async(prompt: string): Promise<string> => {
271+
const AiAssistance = await loadAiAssistanceModule();
272+
const panelInstance = await AiAssistance.AiAssistancePanel.instance();
273+
return await panelInstance.debugProblem(prompt);
274+
};

0 commit comments

Comments
 (0)