Skip to content

Commit 169b45f

Browse files
Samiya CaurDevtools-frontend LUCI CQ
authored andcommitted
Send additional context as part of code completion requests in Console
Bug: 441440074 Change-Id: I5488b2403752f6e4e55709fc1a95bcc537a873f9 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6884276 Commit-Queue: Samiya Caur <samiyac@chromium.org> Reviewed-by: Ergün Erdoğmuş <ergunsh@chromium.org> Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
1 parent eb06387 commit 169b45f

File tree

5 files changed

+152
-6
lines changed

5 files changed

+152
-6
lines changed

front_end/core/host/AidaClient.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,27 @@ export enum EditType {
228228
ACCEPT_COMPLETION = 6,
229229
}
230230

231+
export enum Reason {
232+
// Unknown reason.
233+
UNKNOWN = 0,
234+
235+
// The file is currently open.
236+
CURRENTLY_OPEN = 1,
237+
238+
// The file is opened recently.
239+
RECENTLY_OPENED = 2,
240+
241+
// The file is edited recently.
242+
RECENTLY_EDITED = 3,
243+
244+
// The file is located within the same directory.
245+
COLOCATED = 4,
246+
247+
// Included based on relation to code around the cursor (e.g: could be
248+
// provided by local IDE analysis)
249+
RELATED_FILE = 5,
250+
}
251+
231252
/* eslint-disable @typescript-eslint/naming-convention */
232253
export interface CompletionRequest {
233254
client: string;
@@ -236,6 +257,11 @@ export interface CompletionRequest {
236257
options?: CompleteCodeOptions;
237258
metadata: RequestMetadata;
238259
last_user_action?: EditType;
260+
additional_files?: Array<{
261+
path: string,
262+
content: string,
263+
included_reason: Reason,
264+
}>;
239265
}
240266
/* eslint-enable @typescript-eslint/naming-convention */
241267

front_end/models/ai_code_completion/AiCodeCompletion.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
3737
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
3838
{aidaClient: mockAidaClient},
3939
sinon.createStubInstance(TextEditor.TextEditor.TextEditor),
40+
AiCodeCompletion.Panel.CONSOLE,
4041
['\n'],
4142
);
4243

@@ -71,6 +72,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
7172
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
7273
{aidaClient: mockAidaClient},
7374
editor,
75+
AiCodeCompletion.Panel.CONSOLE,
7476
);
7577

7678
aiCodeCompletion.onTextChanged('prefix', '\n', 1);
@@ -100,6 +102,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
100102
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
101103
{aidaClient: mockAidaClient},
102104
editor,
105+
AiCodeCompletion.Panel.CONSOLE,
103106
);
104107

105108
aiCodeCompletion.onTextChanged('console.log(', ');\n', 1);
@@ -121,6 +124,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
121124
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
122125
{aidaClient: mockAidaClient},
123126
sinon.createStubInstance(TextEditor.TextEditor.TextEditor),
127+
AiCodeCompletion.Panel.CONSOLE,
124128
);
125129

126130
aiCodeCompletion.onTextChanged('p', '', 1);
@@ -151,6 +155,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
151155
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
152156
{aidaClient: mockAidaClient},
153157
editor,
158+
AiCodeCompletion.Panel.CONSOLE,
154159
);
155160
const dispatchSpy = sinon.spy(aiCodeCompletion, 'dispatchEventToListeners');
156161

@@ -183,6 +188,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
183188
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
184189
{aidaClient: mockAidaClient},
185190
editor,
191+
AiCodeCompletion.Panel.CONSOLE,
186192
);
187193
const dispatchSpy = sinon.spy(aiCodeCompletion, 'dispatchEventToListeners');
188194

@@ -210,6 +216,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
210216
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
211217
{aidaClient: mockAidaClient},
212218
editor,
219+
AiCodeCompletion.Panel.CONSOLE,
213220
);
214221

215222
aiCodeCompletion.onTextChanged('prefix', 'suffix', 1);
@@ -252,6 +259,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
252259
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
253260
{aidaClient: mockAidaClient},
254261
editor,
262+
AiCodeCompletion.Panel.CONSOLE,
255263
);
256264

257265
aiCodeCompletion.onTextChanged('prefix ', 'suffix', 1);
@@ -289,6 +297,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
289297
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
290298
{aidaClient: mockAidaClient},
291299
editor,
300+
AiCodeCompletion.Panel.CONSOLE,
292301
);
293302

294303
aiCodeCompletion.onTextChanged('prefix', 'suffix', 1);
@@ -315,6 +324,7 @@ describeWithEnvironment('AiCodeCompletion', () => {
315324
const aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion(
316325
{aidaClient: mockAidaClient},
317326
editor,
327+
AiCodeCompletion.Panel.CONSOLE,
318328
);
319329

320330
aiCodeCompletion.onTextChanged('prefix', 'suffix', 1);

front_end/models/ai_code_completion/AiCodeCompletion.ts

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,99 @@ interface CachedRequest {
3030
response: Host.AidaClient.CompletionResponse;
3131
}
3232

33+
/* clang-format off */
34+
const consoleAdditionalContextFileContent = `/**
35+
* This file describes the execution environment of the Chrome DevTools Console.
36+
* The code is JavaScript, but with special global functions and variables.
37+
* Top-level await is available.
38+
* The console has direct access to the inspected page's \`window\` and \`document\`.
39+
*/
40+
41+
/**
42+
* @description Returns the value of the most recently evaluated expression.
43+
*/
44+
let $_;
45+
46+
/**
47+
* @description A reference to the most recently selected DOM element.
48+
* $0, $1, $2, $3, $4 can be used to reference the last five selected DOM elements.
49+
*/
50+
let $0;
51+
52+
/**
53+
* @description A query selector alias. $$('.my-class') is equivalent to document.querySelectorAll('.my-class').
54+
*/
55+
function $$(selector, startNode) {}
56+
57+
/**
58+
* @description An XPath selector. $x('//p') returns an array of all <p> elements.
59+
*/
60+
function $x(path, startNode) {}
61+
62+
function clear() {}
63+
64+
function copy(object) {}
65+
66+
/**
67+
* @description Selects and reveals the specified element in the Elements panel.
68+
*/
69+
function inspect(object) {}
70+
71+
function keys(object) {}
72+
73+
function values(object) {}
74+
75+
/**
76+
* @description When the specified function is called, the debugger is invoked.
77+
*/
78+
function debug(func) {}
79+
80+
/**
81+
* @description Stops the debugging of the specified function.
82+
*/
83+
function undebug(func) {}
84+
85+
/**
86+
* @description Logs a message to the console whenever the specified function is called,
87+
* along with the arguments passed to it.
88+
*/
89+
function monitor(func) {}
90+
91+
/**
92+
* @description Stops monitoring the specified function.
93+
*/
94+
function unmonitor(func) {}
95+
96+
/**
97+
* @description Logs all events dispatched to the specified object to the console.
98+
*/
99+
function monitorEvents(object, events) {}
100+
101+
/**
102+
* @description Returns an object containing all event listeners registered on the specified object.
103+
*/
104+
function getEventListeners(object) {}
105+
106+
/**
107+
* The global \`console\` object has several helpful methods
108+
*/
109+
const console = {
110+
log: (...args) => {},
111+
warn: (...args) => {},
112+
error: (...args) => {},
113+
info: (...args) => {},
114+
debug: (...args) => {},
115+
assert: (assertion, ...args) => {},
116+
dir: (object) => {}, // Displays an interactive property listing of an object.
117+
dirxml: (object) => {}, // Displays an XML/HTML representation of an object.
118+
table: (data, columns) => {}, // Displays tabular data as a table.
119+
group: (label) => {}, // Creates a new inline collapsible group.
120+
groupEnd: () => {},
121+
time: (label) => {}, // Starts a timer.
122+
timeEnd: (label) => {} // Stops a timer and logs the elapsed time.
123+
};`;
124+
/* clang-format on */
125+
33126
/**
34127
* The AiCodeCompletion class is responsible for fetching code completion suggestions
35128
* from the AIDA backend and displaying them in the text editor.
@@ -50,16 +143,18 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
50143
#stopSequences: string[];
51144
#renderingTimeout?: number;
52145
#aidaRequestCache?: CachedRequest;
146+
#panel: Panel;
53147

54148
readonly #sessionId: string = crypto.randomUUID();
55149
readonly #aidaClient: Host.AidaClient.AidaClient;
56150
readonly #serverSideLoggingEnabled: boolean;
57151

58-
constructor(opts: AgentOptions, editor: TextEditor.TextEditor.TextEditor, stopSequences?: string[]) {
152+
constructor(opts: AgentOptions, editor: TextEditor.TextEditor.TextEditor, panel: Panel, stopSequences?: string[]) {
59153
super();
60154
this.#aidaClient = opts.aidaClient;
61155
this.#serverSideLoggingEnabled = opts.serverSideLoggingEnabled ?? false;
62156
this.#editor = editor;
157+
this.#panel = panel;
63158
this.#stopSequences = stopSequences ?? [];
64159
}
65160

@@ -77,6 +172,14 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
77172
function validTemperature(temperature: number|undefined): number|undefined {
78173
return typeof temperature === 'number' && temperature >= 0 ? temperature : undefined;
79174
}
175+
176+
const additionalFiles = this.#panel === Panel.CONSOLE ? [{
177+
path: 'devtools-console-context.js',
178+
content: consoleAdditionalContextFileContent,
179+
included_reason: Host.AidaClient.Reason.RELATED_FILE,
180+
}] :
181+
undefined;
182+
80183
return {
81184
client: Host.AidaClient.CLIENT_NAME,
82185
prefix,
@@ -93,6 +196,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
93196
user_tier: userTier,
94197
client_version: Root.Runtime.getChromeVersion(),
95198
},
199+
additional_files: additionalFiles,
96200
};
97201
}
98202

@@ -160,7 +264,8 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
160264
} else {
161265
this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
162266
}
163-
} catch {
267+
} catch (e) {
268+
debugLog('Error while fetching code completion suggestions from AIDA', e);
164269
this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
165270
}
166271
}
@@ -273,6 +378,11 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
273378
}
274379
}
275380

381+
export const enum Panel {
382+
CONSOLE = 'console',
383+
SOURCES = 'sources',
384+
}
385+
276386
export const enum Events {
277387
RESPONSE_RECEIVED = 'ResponseReceived',
278388
REQUEST_TRIGGERED = 'RequestTriggered',

front_end/panels/console/ConsolePrompt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,8 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
513513
this.teaser = undefined;
514514
}
515515
// We are prioritizing single line suggestions in Console panel to reduce noise.
516-
this.aiCodeCompletion =
517-
new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion({aidaClient: this.aidaClient}, this.editor, ['\n']);
516+
this.aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
517+
{aidaClient: this.aidaClient}, this.editor, AiCodeCompletion.AiCodeCompletion.Panel.CONSOLE, ['\n']);
518518
this.aiCodeCompletion.addEventListener(AiCodeCompletion.AiCodeCompletion.Events.RESPONSE_RECEIVED, event => {
519519
this.aiCodeCompletionCitations = event.data.citations;
520520
this.dispatchEventToListeners(Events.AI_CODE_COMPLETION_RESPONSE_RECEIVED, event.data);

front_end/panels/sources/AiCodeCompletionPlugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ export class AiCodeCompletionPlugin extends Plugin {
203203
this.#detachAiCodeCompletionTeaser();
204204
this.#teaser = undefined;
205205
}
206-
this.#aiCodeCompletion =
207-
new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion({aidaClient: this.#aidaClient}, this.#editor);
206+
this.#aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
207+
{aidaClient: this.#aidaClient}, this.#editor, AiCodeCompletion.AiCodeCompletion.Panel.SOURCES);
208208
this.#aiCodeCompletion.addEventListener(
209209
AiCodeCompletion.AiCodeCompletion.Events.REQUEST_TRIGGERED, this.#onAiRequestTriggered, this);
210210
this.#aiCodeCompletion.addEventListener(

0 commit comments

Comments
 (0)