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
parent
0857a10f31
commit
52cf5fb613
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue