Skip to content

Commit

Permalink
chore(monacopilot): deprecate and add register completion option
Browse files Browse the repository at this point in the history
  • Loading branch information
arshad-yaseen committed Sep 26, 2024
1 parent 2f56ce0 commit f356c52
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 34 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- [Manually Trigger Completions](#manually-trigger-completions)
- [Trigger Completions with a Keyboard Shortcut](#trigger-completions-with-a-keyboard-shortcut)
- [Trigger Completions with an Editor Action](#trigger-completions-with-an-editor-action)
- [External Context](#external-context)
- [Multi-File Context](#multi-file-context)
- [Filename](#filename)
- [Completions for Specific Technologies](#completions-for-specific-technologies)
- [Max Context Lines](#max-context-lines)
Expand Down Expand Up @@ -197,13 +197,13 @@ monaco.editor.addEditorAction({
});
```

### External Context
### Multi-File Context

Enhance the accuracy and relevance of Copilot's completions by providing additional code context from your workspace.
Improve the quality and relevance of Copilot's suggestions by providing additional code context from other files in your project. This feature allows Copilot to understand the broader scope of your codebase, resulting in more accurate and contextually appropriate completions.

```javascript
registerCompletion(monaco, editor, {
externalContext: [
relatedFiles: [
{
path: './utils.js',
content:
Expand All @@ -213,7 +213,7 @@ registerCompletion(monaco, editor, {
});
```

By providing external context, Copilot can offer more intelligent suggestions. For example, if you start typing `const isPalindrome = `, Copilot may suggest using the `reverse` function from `utils.js`.
For instance, if you begin typing `const isPalindrome = ` in your current file, Copilot will recognize the `reverse` function from the `utils.js` file you provided earlier. It will then suggest a completion that utilizes this function.

### Filename

Expand Down Expand Up @@ -396,7 +396,7 @@ The `customPrompt` function receives a `completionMetadata` object, which contai
| `cursorPosition` | `{ lineNumber: number; column: number }` | The current cursor position in the editor. |
| `filename` | `string` or `undefined` | The name of the file being edited. Only available if you have provided the `filename` option in the `registerCompletion` function. |
| `technologies` | `string[]` or `undefined` | An array of technologies used in the project. Only available if you have provided the `technologies` option in the `registerCompletion` function. |
| `externalContext` | `object` or `undefined` | Additional context from related files. Only available if you have provided the `externalContext` option in the `registerCompletion` function. |
| `context` | `object` or `undefined` | Additional context from related files. Only available if you have provided the `context` option in the `registerCompletion` function. |
| `textAfterCursor` | `string` | The text that appears after the cursor. |
| `textBeforeCursor` | `string` | The text that appears before the cursor. |
| `editorState` | `object` | An object containing the `completionMode` property. |
Expand Down
5 changes: 5 additions & 0 deletions src/core/completion/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ const handleInlineCompletions = async ({
}: InlineCompletionHandlerParams): Promise<EditorInlineCompletionsResult> => {
const {trigger = TriggerType.OnIdle, ...restOptions} = options;

// handle the deprecated `externalContext` option until it's removed
if (restOptions.externalContext) {
restOptions.relatedFiles = restOptions.externalContext;
}

if (!new CompletionValidator(pos, mdl).shouldProvideCompletions()) {
return createInlineCompletionResult([]);
}
Expand Down
32 changes: 16 additions & 16 deletions src/helpers/completion/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
CompletionResponse,
CursorPosition,
EditorModel,
ExternalContext,
FetchCompletionItemParams,
RelatedFile,
} from '../../types';
import {
getCharAfterCursor,
Expand All @@ -30,7 +30,7 @@ export const fetchCompletionItem = async ({
endpoint,
language,
technologies,
externalContext,
relatedFiles,
mdl,
pos,
maxContextLines,
Expand All @@ -48,7 +48,7 @@ export const fetchCompletionItem = async ({
mdl,
language,
technologies,
externalContext,
relatedFiles,
maxContextLines,
}),
},
Expand All @@ -75,17 +75,17 @@ export const constructCompletionMetadata = ({
mdl,
language,
technologies,
externalContext,
relatedFiles,
maxContextLines,
}: Omit<
FetchCompletionItemParams,
'text' | 'endpoint' | 'token' | 'abortSignal'
>): CompletionMetadata => {
const completionMode = determineCompletionMode(pos, mdl);

// Determine the divisor based on the presence of external contexts
const hasExternalContext = !!externalContext?.length;
const divisor = hasExternalContext ? 3 : 2;
// Determine the divisor based on the presence of related files
const hasRelatedFiles = !!relatedFiles?.length;
const divisor = hasRelatedFiles ? 3 : 2;
const adjustedMaxContextLines = maxContextLines
? Math.floor(maxContextLines / divisor)
: undefined;
Expand All @@ -99,13 +99,13 @@ export const constructCompletionMetadata = ({
return maxLines ? keepNLines(text, maxLines, options) : text;
};

const processExternalContexts = (
contexts?: ExternalContext[],
const processRelatedFiles = (
files?: RelatedFile[],
maxLines?: number,
): ExternalContext[] | undefined => {
if (!contexts || !maxLines) return contexts;
): RelatedFile[] | undefined => {
if (!files || !maxLines) return files;

return contexts.map(({content, ...rest}) => ({
return files.map(({content, ...rest}) => ({
...rest,
content: keepNLines(content, maxLines),
}));
Expand All @@ -124,17 +124,17 @@ export const constructCompletionMetadata = ({
adjustedMaxContextLines,
);

// Process external contexts with the adjusted maximum lines
const limitedExternalContext = processExternalContexts(
externalContext,
// Process related files with the adjusted maximum lines
const limitedRelatedFiles = processRelatedFiles(
relatedFiles,
adjustedMaxContextLines,
);

return {
filename,
language,
technologies,
externalContext: limitedExternalContext,
relatedFiles: limitedRelatedFiles,
textBeforeCursor,
textAfterCursor,
cursorPosition: pos,
Expand Down
14 changes: 7 additions & 7 deletions src/helpers/completion/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const createUserPrompt = (metadata: CompletionMetadata): string => {
filename = '/',
textBeforeCursor = '',
textAfterCursor = '',
externalContext,
relatedFiles,
editorState,
} = metadata;

Expand All @@ -58,7 +58,7 @@ const createUserPrompt = (metadata: CompletionMetadata): string => {
<guidelines>
<instruction>${specificInstruction}</instruction>
<steps>
<step>Analyze the provided code and any external files thoroughly.</step>
<step>Analyze the provided code and any related files thoroughly.</step>
<step>Ensure the generated code integrates seamlessly with the existing code.</step>
<step>Adhere to best practices and maintain consistent coding style.</step>
<step>Do <strong>not</strong> include the code before the cursor in your response.</step>
Expand All @@ -80,15 +80,15 @@ ${textBeforeCursor}${CURSOR_PLACEHOLDER}${textAfterCursor}
</context>
`;

const externalFiles =
externalContext
const relatedFilesText =
relatedFiles
?.map(
({path, content}) => `
<external_file path="${path}">
<related_file path="${path}">
<code>
${content}
</code>
</external_file>
</related_file>
`,
)
.join('\n') || '';
Expand All @@ -97,7 +97,7 @@ ${content}
<task>
${guidelines}
${codeContext}
${externalFiles}
${relatedFilesText}
</task>
`;
};
Expand Down
13 changes: 9 additions & 4 deletions src/types/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
export type Endpoint = string;
export type Filename = string;
export type Technologies = string[];
export type ExternalContext = {
export type RelatedFile = {
/**
* The relative path from the current editing code in the editor to an external file.
*
Expand Down Expand Up @@ -64,11 +64,16 @@ export interface RegisterCompletionOptions {
* etc.
*/
technologies?: Technologies;
/**
* @deprecated
* Use `relatedFiles` instead.
*/
externalContext?: RelatedFile[];
/**
* Helps to give more relevant completions based on the full context.
* You can include things like the contents/codes of other files in the same workspace.
*/
externalContext?: ExternalContext[];
relatedFiles?: RelatedFile[];
/**
* The maximum number of lines of code to include in the completion request.
* This limits the request size to the model to prevent `429 Too Many Requests` errors
Expand Down Expand Up @@ -175,7 +180,7 @@ export interface CompletionMetadata {
/**
* Additional context from related files.
*/
externalContext: ExternalContext[] | undefined;
relatedFiles: RelatedFile[] | undefined;
/**
* The text that appears after the cursor.
*/
Expand Down Expand Up @@ -207,7 +212,7 @@ export interface FetchCompletionItemParams {
endpoint: Endpoint;
filename?: Filename;
technologies?: Technologies;
externalContext?: ExternalContext[];
relatedFiles?: RelatedFile[];
maxContextLines?: number;
mdl: EditorModel;
pos: CursorPosition;
Expand Down
2 changes: 1 addition & 1 deletion tests/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const mockCompletionMetadata: CompletionMetadata = {
cursorPosition: {lineNumber: 1, column: 1},
filename: 'test.js',
technologies: ['react'],
externalContext: [{path: './utils.js', content: 'function test() {}'}],
relatedFiles: [{path: './utils.js', content: 'function test() {}'}],
textAfterCursor: 'console.log(',
textBeforeCursor: 'function hello() {',
editorState: {
Expand Down

0 comments on commit f356c52

Please sign in to comment.