Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions clients/tabby-agent/openapi/tabby.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"info": {
"title": "Tabby Server",
"description": "\n[![tabby stars](https://img.shields.io/github/stars/TabbyML/tabby)](https://github.com/TabbyML/tabby)\n[![Join Slack](https://shields.io/badge/Join-Tabby%20Slack-red?logo=slack)](https://links.tabbyml.com/join-slack)\n\nInstall following IDE / Editor extensions to get started with [Tabby](https://github.com/TabbyML/tabby).\n* [VSCode Extension](https://github.com/TabbyML/tabby/tree/main/clients/vscode) – Install from the [marketplace](https://marketplace.visualstudio.com/items?itemName=TabbyML.vscode-tabby), or [open-vsx.org](https://open-vsx.org/extension/TabbyML/vscode-tabby)\n* [VIM Extension](https://github.com/TabbyML/tabby/tree/main/clients/vim)\n* [IntelliJ Platform Plugin](https://github.com/TabbyML/tabby/tree/main/clients/intellij) – Install from the [marketplace](https://plugins.jetbrains.com/plugin/22379-tabby)\n",
"contact": { "name": "TabbyML Team" },
"license": { "name": "Apache 2.0", "url": "https://github.com/TabbyML/tabby/blob/main/LICENSE" },
"version": "0.10.0-dev.0"
},
Expand Down Expand Up @@ -80,13 +81,13 @@
"name": "limit",
"in": "query",
"required": false,
"schema": { "type": "integer", "default": 20, "nullable": true, "minimum": 0.0 }
"schema": { "type": "integer", "default": 20, "nullable": true, "minimum": 0 }
},
{
"name": "offset",
"in": "query",
"required": false,
"schema": { "type": "integer", "default": 0, "nullable": true, "minimum": 0.0 }
"schema": { "type": "integer", "default": 0, "nullable": true, "minimum": 0 }
}
],
"responses": {
Expand Down Expand Up @@ -119,7 +120,7 @@
"type": "object",
"required": ["index", "delta"],
"properties": {
"index": { "type": "integer", "minimum": 0.0 },
"index": { "type": "integer", "minimum": 0 },
"logprobs": { "type": "string", "nullable": true },
"finish_reason": { "type": "string", "nullable": true },
"delta": { "$ref": "#/components/schemas/ChatCompletionDelta" }
Expand All @@ -130,7 +131,7 @@
"required": ["id", "created", "system_fingerprint", "object", "model", "choices"],
"properties": {
"id": { "type": "string" },
"created": { "type": "integer", "format": "int64", "minimum": 0.0 },
"created": { "type": "integer", "format": "int64", "minimum": 0 },
"system_fingerprint": { "type": "string" },
"object": { "type": "string" },
"model": { "type": "string" },
Expand All @@ -148,7 +149,7 @@
"properties": {
"messages": { "type": "array", "items": { "$ref": "#/components/schemas/Message" } },
"temperature": { "type": "number", "format": "float", "nullable": true },
"seed": { "type": "integer", "format": "int64", "nullable": true, "minimum": 0.0 }
"seed": { "type": "integer", "format": "int64", "nullable": true, "minimum": 0 }
},
"example": {
"messages": [
Expand All @@ -161,10 +162,7 @@
"Choice": {
"type": "object",
"required": ["index", "text"],
"properties": {
"index": { "type": "integer", "format": "int32", "minimum": 0.0 },
"text": { "type": "string" }
}
"properties": { "index": { "type": "integer", "format": "int32", "minimum": 0 }, "text": { "type": "string" } }
},
"CompletionRequest": {
"type": "object",
Expand Down Expand Up @@ -193,7 +191,7 @@
"format": "int64",
"description": "The seed used for randomly selecting tokens",
"nullable": true,
"minimum": 0.0
"minimum": 0
}
},
"example": {
Expand Down Expand Up @@ -241,7 +239,7 @@
"properties": {
"filepath": {
"type": "string",
"description": "Filepath of the file where the snippet is from.\n- When the file belongs to the same workspace as the current file,\nthis is a relative filepath, that has the same root as the current file.\n- When the file located outside the workspace, such as in a dependency package,\nthis is a file URI with an absolute filepath."
"description": "Filepath of the file where the snippet is from.\n- When the file belongs to the same workspace as the current file,\nthis is a relative filepath, use the same rule as [Segments::filepath].\n- When the file located outside the workspace, such as in a dependency package,\nthis is a file URI with an absolute filepath."
},
"body": { "type": "string", "description": "Body of the snippet." }
}
Expand All @@ -255,7 +253,7 @@
"device": { "type": "string" },
"arch": { "type": "string" },
"cpu_info": { "type": "string" },
"cpu_count": { "type": "integer", "minimum": 0.0 },
"cpu_count": { "type": "integer", "minimum": 0 },
"cuda_devices": { "type": "array", "items": { "type": "string" } },
"version": { "$ref": "#/components/schemas/Version" }
}
Expand All @@ -266,7 +264,7 @@
"properties": {
"score": { "type": "number", "format": "float" },
"doc": { "$ref": "#/components/schemas/HitDocument" },
"id": { "type": "integer", "format": "int32", "minimum": 0.0 }
"id": { "type": "integer", "format": "int32", "minimum": 0 }
}
},
"HitDocument": {
Expand All @@ -291,9 +289,9 @@
"example": "view"
},
"completion_id": { "type": "string" },
"choice_index": { "type": "integer", "format": "int32", "minimum": 0.0 },
"choice_index": { "type": "integer", "format": "int32", "minimum": 0 },
"view_id": { "type": "string", "nullable": true },
"elapsed": { "type": "integer", "format": "int32", "nullable": true, "minimum": 0.0 }
"elapsed": { "type": "integer", "format": "int32", "nullable": true, "minimum": 0 }
}
},
"Message": {
Expand All @@ -305,7 +303,7 @@
"type": "object",
"required": ["num_hits", "hits"],
"properties": {
"num_hits": { "type": "integer", "minimum": 0.0 },
"num_hits": { "type": "integer", "minimum": 0 },
"hits": { "type": "array", "items": { "$ref": "#/components/schemas/Hit" } }
}
},
Expand All @@ -321,7 +319,7 @@
},
"filepath": {
"type": "string",
"description": "The relative path of the file that is being edited.\n- When `git_url` is set, this is the path of the file in the git repository.\n- When `git_url` is empty, this is the path of the file in the workspace.",
"description": "The relative path of the file that is being edited.\n- When [Segments::git_url] is set, this is the path of the file in the git repository.\n- When [Segments::git_url] is empty, this is the path of the file in the workspace.",
"nullable": true
},
"git_url": {
Expand All @@ -332,7 +330,13 @@
"declarations": {
"type": "array",
"items": { "$ref": "#/components/schemas/Declaration" },
"description": "The relevant declaration code snippets provided by editor.\nIt'll contains declarations extracted from `prefix` segments using LSP.",
"description": "The relevant declaration code snippets provided by the editor's LSP,\ncontain declarations of symbols extracted from [Segments::prefix].",
"nullable": true
},
"relevant_snippets_from_changed_files": {
"type": "array",
"items": { "$ref": "#/components/schemas/Snippet" },
"description": "The relevant code snippets extracted from recently edited files.\nThese snippets are selected from candidates found within code chunks\nbased on the edited location.\nThe current editing file is excluded from the search candidates.\n\nWhen provided alongside [Segments::declarations], the snippets have\nalready been deduplicated to ensure no duplication with entries\nin [Segments::declarations].\n\nSorted in descending order of [Snippet::score].",
"nullable": true
},
"clipboard": {
Expand Down
37 changes: 37 additions & 0 deletions clients/tabby-agent/src/AgentConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,30 @@ export type AgentConfig = {
// max number of characters per snippet
maxCharsPerSnippet: number;
};
collectSnippetsFromRecentChangedFiles: {
enabled: boolean;
// max number of snippets
maxSnippets: number;
indexing: {
// Interval in ms for indexing worker to check pending task
checkingChangesInterval: number;
// Debouncing interval in ms for sending changes to indexing task
changesDebouncingInterval: number;

// Determine the crop window at changed location for indexing
// Line before changed location
prefixLines: number;
// Line after changed location
suffixLines: number;

// Max number of chunks in memory
maxChunks: number;
// chars per code chunk
chunkSize: number;
// overlap lines between neighbor chunks
overlapLines: number;
};
};
clipboard: {
minChars: number;
maxChars: number;
Expand Down Expand Up @@ -82,6 +106,19 @@ export const defaultAgentConfig: AgentConfig = {
maxSnippets: 5,
maxCharsPerSnippet: 500,
},
collectSnippetsFromRecentChangedFiles: {
enabled: false,
maxSnippets: 3,
indexing: {
checkingChangesInterval: 500,
changesDebouncingInterval: 1000,
prefixLines: 20,
suffixLines: 20,
maxChunks: 100,
chunkSize: 500,
overlapLines: 1,
},
},
clipboard: {
minChars: 3,
maxChars: 2000,
Expand Down
12 changes: 12 additions & 0 deletions clients/tabby-agent/src/CompletionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ export type CompletionRequest = {
}[];
};
declarations?: Declaration[];
relevantSnippetsFromChangedFiles?: CodeSnippet[];
};

export type Declaration = {
filepath: string;
offset: number;
text: string;
};

export type CodeSnippet = {
filepath: string;
offset: number;
text: string;
score: number;
};

export type CompletionResponseChoice = {
index: number;
text: string;
Expand Down Expand Up @@ -71,6 +80,7 @@ export class CompletionContext {
};

declarations?: Declaration[];
relevantSnippetsFromChangedFiles?: CodeSnippet[];

// "default": the cursor is at the end of the line
// "fill-in-line": the cursor is not at the end of the line, except auto closed characters
Expand Down Expand Up @@ -98,6 +108,7 @@ export class CompletionContext {
this.git = request.git;

this.declarations = request.declarations;
this.relevantSnippetsFromChangedFiles = request.relevantSnippetsFromChangedFiles;

const lineEnd = isAtLineEndExcludingAutoClosedChar(this.suffixLines[0] ?? "");
this.mode = lineEnd ? "default" : "fill-in-line";
Expand All @@ -108,6 +119,7 @@ export class CompletionContext {
position: this.position,
clipboard: this.clipboard,
declarations: this.declarations,
relevantSnippetsFromChangedFiles: this.relevantSnippetsFromChangedFiles,
});
}
}
29 changes: 29 additions & 0 deletions clients/tabby-agent/src/TabbyAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,34 @@ export class TabbyAgent extends EventEmitter implements Agent {
};
});

// snippets
const relevantSnippetsFromChangedFiles = context.relevantSnippetsFromChangedFiles
// deduplicate
?.filter(
(snippet) =>
// Remove snippet if find a declaration from the same file and range is overlapping
!context.declarations?.find((declaration) => {
return (
declaration.filepath === snippet.filepath &&
// Is range overlapping
Math.max(declaration.offset, snippet.offset) <=
Math.min(declaration.offset + declaration.text.length, snippet.offset + snippet.text.length)
);
}),
)
.map((snippet) => {
let snippetFilepath = snippet.filepath;
if (relativeFilepathRoot && snippetFilepath.startsWith(relativeFilepathRoot)) {
snippetFilepath = path.relative(relativeFilepathRoot, snippetFilepath);
}
return {
filepath: snippetFilepath,
body: snippet.text,
score: snippet.score,
};
})
.sort((a, b) => b.score - a.score);

// clipboard
let clipboard = undefined;
const clipboardConfig = this.config.completion.prompt.clipboard;
Expand All @@ -386,6 +414,7 @@ export class TabbyAgent extends EventEmitter implements Agent {
filepath,
git_url: gitUrl,
declarations,
relevant_snippets_from_changed_files: relevantSnippetsFromChangedFiles,
clipboard,
};
}
Expand Down
19 changes: 15 additions & 4 deletions clients/tabby-agent/src/configFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,21 @@ const typeCheckSchema: Record<string, string> = {
"completion.prompt.experimentalStripAutoClosingCharacters": "boolean",
"completion.prompt.maxPrefixLines": "number",
"completion.prompt.maxSuffixLines": "number",
"completion.prompt.experimentalDeclarations": "object",
"completion.prompt.experimentalDeclarations.enabled": "boolean",
"completion.prompt.experimentalDeclarations.maxSnippets": "number",
"completion.prompt.experimentalDeclarations.maxChars": "number",
"completion.prompt.fillDeclarations": "object",
"completion.prompt.fillDeclarations.enabled": "boolean",
"completion.prompt.fillDeclarations.maxSnippets": "number",
"completion.prompt.fillDeclarations.maxChars": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles": "object",
"completion.prompt.collectSnippetsFromRecentChangedFiles.enabled": "boolean",
"completion.prompt.collectSnippetsFromRecentChangedFiles.maxSnippets": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing": "object",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.checkingChangesInterval": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.changesDebouncingInterval": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.prefixLines": "boolean",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.suffixLines": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.maxChunks": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.chunkSize": "number",
"completion.prompt.collectSnippetsFromRecentChangedFiles.indexing.overlapLines": "number",
"completion.prompt.clipboard": "object",
"completion.prompt.clipboard.minChars": "number",
"completion.prompt.clipboard.maxChars": "number",
Expand Down
23 changes: 18 additions & 5 deletions clients/tabby-agent/src/types/tabbyApi.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export interface components {
/**
* @description Filepath of the file where the snippet is from.
* - When the file belongs to the same workspace as the current file,
* this is a relative filepath, that has the same root as the current file.
* this is a relative filepath, use the same rule as [Segments::filepath].
* - When the file located outside the workspace, such as in a dependency package,
* this is a file URI with an absolute filepath.
*/
Expand Down Expand Up @@ -212,8 +212,8 @@ export interface components {
suffix?: string | null;
/**
* @description The relative path of the file that is being edited.
* - When `git_url` is set, this is the path of the file in the git repository.
* - When `git_url` is empty, this is the path of the file in the workspace.
* - When [Segments::git_url] is set, this is the path of the file in the git repository.
* - When [Segments::git_url] is empty, this is the path of the file in the workspace.
*/
filepath?: string | null;
/**
Expand All @@ -223,10 +223,23 @@ export interface components {
*/
git_url?: string | null;
/**
* @description The relevant declaration code snippets provided by editor.
* It'll contains declarations extracted from `prefix` segments using LSP.
* @description The relevant declaration code snippets provided by the editor's LSP,
* contain declarations of symbols extracted from [Segments::prefix].
*/
declarations?: components["schemas"]["Declaration"][] | null;
/**
* @description The relevant code snippets extracted from recently edited files.
* These snippets are selected from candidates found within code chunks
* based on the edited location.
* The current editing file is excluded from the search candidates.
*
* When provided alongside [Segments::declarations], the snippets have
* already been deduplicated to ensure no duplication with entries
* in [Segments::declarations].
*
* Sorted in descending order of [Snippet::score].
*/
relevant_snippets_from_changed_files?: components["schemas"]["Snippet"][] | null;
/** @description Clipboard content when requesting code completion. */
clipboard?: string | null;
};
Expand Down
1 change: 1 addition & 0 deletions clients/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
"typescript": "^5.3.2"
},
"dependencies": {
"@orama/orama": "^2.0.15",
"@xstate/fsm": "^2.0.1",
"tabby-agent": "1.5.0-dev"
}
Expand Down
Loading