feat(agent): support read clipboard as prompt (#885)

* feat(agent): add support for reading clipboard text as prompt.

* fix: add clipboard in context hash calculation.

* fix: set default allowed clipboard chars to 2000.
wsxiaoys-patch-3
Zhiming Ma 2023-11-24 14:56:31 +08:00 committed by GitHub
parent 0857a10f31
commit 52cf5fb613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 34 additions and 12 deletions

View File

@ -10,6 +10,6 @@
"devDependencies": { "devDependencies": {
"cpy-cli": "^4.2.0", "cpy-cli": "^4.2.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"tabby-agent": "1.1.1" "tabby-agent": "1.2.0-dev"
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "tabby-agent", "name": "tabby-agent",
"version": "1.1.1", "version": "1.2.0-dev",
"description": "Generic client agent for Tabby AI coding assistant IDE extensions.", "description": "Generic client agent for Tabby AI coding assistant IDE extensions.",
"repository": "https://github.com/TabbyML/tabby", "repository": "https://github.com/TabbyML/tabby",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@ -13,6 +13,10 @@ export type AgentConfig = {
experimentalStripAutoClosingCharacters: boolean; experimentalStripAutoClosingCharacters: boolean;
maxPrefixLines: number; maxPrefixLines: number;
maxSuffixLines: number; maxSuffixLines: number;
clipboard: {
minChars: number;
maxChars: number;
};
}; };
debounce: { debounce: {
mode: "adaptive" | "fixed"; mode: "adaptive" | "fixed";
@ -66,6 +70,10 @@ export const defaultAgentConfig: AgentConfig = {
experimentalStripAutoClosingCharacters: false, experimentalStripAutoClosingCharacters: false,
maxPrefixLines: 20, maxPrefixLines: 20,
maxSuffixLines: 20, maxSuffixLines: 20,
clipboard: {
minChars: 3,
maxChars: 2000,
},
}, },
debounce: { debounce: {
mode: "adaptive", mode: "adaptive",

View File

@ -1,4 +1,4 @@
import { splitLines, autoClosingPairOpenings, autoClosingPairClosings } from "./utils"; import { splitLines, autoClosingPairClosings } from "./utils";
import hashObject from "object-hash"; import hashObject from "object-hash";
export type CompletionRequest = { export type CompletionRequest = {
@ -6,6 +6,7 @@ export type CompletionRequest = {
language: string; language: string;
text: string; text: string;
position: number; position: number;
clipboard?: string;
manually?: boolean; manually?: boolean;
}; };
@ -43,6 +44,8 @@ export class CompletionContext {
prefixLines: string[]; prefixLines: string[];
suffixLines: string[]; suffixLines: string[];
clipboard: string;
// "default": the cursor is at the end of the line // "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 // "fill-in-line": the cursor is not at the end of the line, except auto closed characters
// In this case, we assume the completion should be a single line, so multiple lines completion will be dropped. // In this case, we assume the completion should be a single line, so multiple lines completion will be dropped.
@ -60,13 +63,16 @@ export class CompletionContext {
this.prefixLines = splitLines(this.prefix); this.prefixLines = splitLines(this.prefix);
this.suffixLines = splitLines(this.suffix); this.suffixLines = splitLines(this.suffix);
this.clipboard = request.clipboard?.trim() ?? "";
const lineEnd = isAtLineEndExcludingAutoClosedChar(this.suffixLines[0] ?? ""); const lineEnd = isAtLineEndExcludingAutoClosedChar(this.suffixLines[0] ?? "");
this.mode = lineEnd ? "default" : "fill-in-line"; this.mode = lineEnd ? "default" : "fill-in-line";
this.hash = hashObject({ this.hash = hashObject({
filepath: request.filepath, filepath: this.filepath,
language: request.language, language: this.language,
text: request.text, text: this.text,
position: request.position, position: this.position,
clipboard: this.clipboard,
}); });
} }
} }

View File

@ -275,7 +275,7 @@ export class TabbyAgent extends EventEmitter implements Agent {
} }
} }
private createSegments(context: CompletionContext): { prefix: string; suffix: string } { private createSegments(context: CompletionContext): { prefix: string; suffix: string; clipboard?: string } {
// max lines in prefix and suffix configurable // max lines in prefix and suffix configurable
const maxPrefixLines = this.config.completion.prompt.maxPrefixLines; const maxPrefixLines = this.config.completion.prompt.maxPrefixLines;
const maxSuffixLines = this.config.completion.prompt.maxSuffixLines; const maxSuffixLines = this.config.completion.prompt.maxSuffixLines;
@ -287,7 +287,13 @@ export class TabbyAgent extends EventEmitter implements Agent {
} else { } else {
suffix = suffixLines.slice(0, maxSuffixLines).join(""); suffix = suffixLines.slice(0, maxSuffixLines).join("");
} }
return { prefix, suffix };
let clipboard = undefined;
const clipboardConfig = this.config.completion.prompt.clipboard;
if (context.clipboard.length >= clipboardConfig.minChars && context.clipboard.length <= clipboardConfig.maxChars) {
clipboard = context.clipboard;
}
return { prefix, suffix, clipboard };
} }
public async initialize(options: AgentInitOptions): Promise<boolean> { public async initialize(options: AgentInitOptions): Promise<boolean> {

View File

@ -10,6 +10,6 @@
"devDependencies": { "devDependencies": {
"cpy-cli": "^4.2.0", "cpy-cli": "^4.2.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"tabby-agent": "1.1.1" "tabby-agent": "1.2.0-dev"
} }
} }

View File

@ -7,7 +7,7 @@
"repository": "https://github.com/TabbyML/tabby", "repository": "https://github.com/TabbyML/tabby",
"bugs": "https://github.com/TabbyML/tabby/issues", "bugs": "https://github.com/TabbyML/tabby/issues",
"license": "Apache-2.0", "license": "Apache-2.0",
"version": "1.1.3", "version": "1.2.0-dev",
"keywords": [ "keywords": [
"ai", "ai",
"autocomplete", "autocomplete",
@ -226,6 +226,6 @@
}, },
"dependencies": { "dependencies": {
"@xstate/fsm": "^2.0.1", "@xstate/fsm": "^2.0.1",
"tabby-agent": "1.1.1" "tabby-agent": "1.2.0-dev"
} }
} }

View File

@ -7,6 +7,7 @@ import {
Position, Position,
Range, Range,
TextDocument, TextDocument,
env,
workspace, workspace,
} from "vscode"; } from "vscode";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
@ -66,6 +67,7 @@ export class TabbyCompletionProvider extends EventEmitter implements InlineCompl
language: document.languageId, // https://code.visualstudio.com/docs/languages/identifiers language: document.languageId, // https://code.visualstudio.com/docs/languages/identifiers
text: document.getText(), text: document.getText(),
position: document.offsetAt(position), position: document.offsetAt(position),
clipboard: await env.clipboard.readText(),
manually: context.triggerKind === InlineCompletionTriggerKind.Invoke, manually: context.triggerKind === InlineCompletionTriggerKind.Invoke,
}; };