Skip to content

Commit 9868db4

Browse files
authored
update cloud support (#26)
* update cloud support * remove using cloud for completion * remove @xenova/transformers
1 parent a3b151c commit 9868db4

File tree

19 files changed

+2553
-306
lines changed

19 files changed

+2553
-306
lines changed

package-lock.json

Lines changed: 2088 additions & 120 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@
148148
"description": "The directory to use for storing user data associated with this extension. Set to an empty string, `os.homedir()` will be used."
149149
},
150150
"firecoder.cloud.endpoint": {
151+
"type": "string",
152+
"default": "https://llm-api.firecoder.cc/v1",
153+
"description": ""
154+
},
155+
"firecoder.cloud.apiToken": {
151156
"type": "string",
152157
"default": "",
153158
"description": ""
@@ -191,6 +196,8 @@
191196
},
192197
"dependencies": {
193198
"@grafana/faro-core": "^1.3.5",
194-
"@grafana/faro-web-sdk": "^1.3.5"
199+
"@grafana/faro-web-sdk": "^1.3.5",
200+
"@langchain/community": "^0.0.27",
201+
"langchain": "^0.1.17"
195202
}
196-
}
203+
}

src/common/chat/cloudChat.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { ChatOpenAI } from "@langchain/openai";
2+
import { StringOutputParser } from "langchain/schema/output_parser";
3+
import {
4+
AIMessage,
5+
HumanMessage,
6+
SystemMessage,
7+
} from "@langchain/core/messages";
8+
import { HistoryMessage } from "../prompt";
9+
import { configuration } from "../utils/configuration";
10+
11+
type Parameters = {
12+
temperature: number;
13+
n_predict: number;
14+
};
15+
16+
export const sendChatRequestCloud = async (
17+
history: HistoryMessage[],
18+
parameters: Parameters
19+
) => {
20+
const apiKey = configuration.get("cloud.apiToken");
21+
22+
const model = new ChatOpenAI({
23+
maxRetries: 0,
24+
openAIApiKey: apiKey,
25+
configuration: {
26+
baseURL: configuration.get("cloud.endpoint"),
27+
},
28+
temperature: parameters.temperature,
29+
maxTokens: parameters.n_predict,
30+
});
31+
32+
const parser = new StringOutputParser();
33+
34+
const messages = history.map((message) => {
35+
switch (message.role) {
36+
case "ai":
37+
return new AIMessage(message.content);
38+
case "user":
39+
return new HumanMessage(message.content);
40+
case "system":
41+
return new SystemMessage(message.content);
42+
default:
43+
return new HumanMessage(message.content);
44+
}
45+
});
46+
47+
const stream = await model.pipe(parser).stream(messages, {
48+
maxConcurrency: 1,
49+
});
50+
51+
return stream;
52+
};

src/common/chat/index.ts

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import * as vscode from "vscode";
22
import { randomUUID } from "crypto";
3-
import { HistoryMessage, getPromptChat } from "../prompt/promptChat";
3+
import { ChatMessage, getPromptChat } from "../prompt/promptChat";
44
import Logger from "../logger";
5-
import { sendChatRequest } from "./localChat";
6-
import { servers } from "../server";
5+
import { sendChatRequestLocal as sendChatRequestLocal } from "./localChat";
76
import { configuration } from "../utils/configuration";
87
import statusBar from "../statusBar";
8+
import { sendChatRequestCloud } from "./cloudChat";
9+
import {
10+
getHighlightedTextDetails,
11+
humanMessageWithCodePrompt,
12+
systemTemplate,
13+
} from "./utils/useHighlightedTextAsContext";
914

1015
const logCompletion = () => {
1116
const uuid = randomUUID();
@@ -17,37 +22,55 @@ const logCompletion = () => {
1722
};
1823
};
1924

20-
export async function* chat(history: HistoryMessage[]) {
25+
export async function* chat(
26+
history: ChatMessage[],
27+
config?: {
28+
provideHighlightedText?: boolean;
29+
}
30+
) {
2131
const loggerCompletion = logCompletion();
2232

2333
loggerCompletion.info("Chat: started");
2434

25-
const prompt = await getPromptChat(history);
26-
2735
const parameters = {
2836
n_predict: 4096,
2937
stop: [],
3038
temperature: 0.7,
3139
};
3240

33-
const serverUrl = configuration.get("cloud.use")
34-
? configuration.get("cloud.endpoint")
35-
: servers["chat-medium"].serverUrl;
36-
3741
const { stopTask } = statusBar.startTask();
38-
3942
try {
4043
Logger.info(`Start request;`, {
4144
component: "chat",
4245
sendTelemetry: true,
4346
});
4447

45-
yield* sendChatRequest(
46-
prompt,
47-
parameters,
48-
loggerCompletion.uuid(),
49-
serverUrl
50-
);
48+
if (config?.provideHighlightedText) {
49+
const highlighted = getHighlightedTextDetails();
50+
51+
if (highlighted !== null && history.length === 1) {
52+
const firstMessage = history.shift();
53+
history.unshift({
54+
role: "user",
55+
content: await humanMessageWithCodePrompt.format({
56+
highlightedCode: highlighted.content,
57+
question: firstMessage?.content,
58+
}),
59+
});
60+
}
61+
history.unshift({
62+
role: "system",
63+
content: systemTemplate,
64+
});
65+
}
66+
67+
if (configuration.get("cloud.use")) {
68+
yield* await sendChatRequestCloud(history, parameters);
69+
} else {
70+
const prompt = getPromptChat(history);
71+
72+
yield* sendChatRequestLocal(prompt, parameters, loggerCompletion.uuid());
73+
}
5174

5275
loggerCompletion.info("Request: finished");
5376
} catch (error) {

src/common/chat/localChat.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from "vscode";
22
import { randomUUID } from "crypto";
33
import Logger from "../logger";
4+
import { servers } from "../server";
45

56
const logCompletion = (uuid = randomUUID() as string) => {
67
return {
@@ -33,13 +34,13 @@ const defualtParameters = {
3334
slot_id: -1,
3435
};
3536

36-
export async function* sendChatRequest(
37+
export async function* sendChatRequestLocal(
3738
prompt: string,
3839
parameters: Record<string, any>,
39-
uuid: string,
40-
url: string
40+
uuid: string
4141
) {
4242
const loggerCompletion = logCompletion(uuid);
43+
const url = servers["chat-medium"].serverUrl;
4344

4445
const parametersForCompletion = {
4546
...defualtParameters,
@@ -51,14 +52,12 @@ export async function* sendChatRequest(
5152

5253
const startTime = performance.now();
5354

54-
let content = "";
5555
let timings;
5656
for await (const chunk of llama(prompt, parametersForCompletion, { url })) {
5757
// @ts-ignore
5858
if (chunk.data) {
5959
// @ts-ignore
60-
content += chunk.data.content;
61-
yield content;
60+
yield chunk.data.content;
6261
}
6362

6463
// @ts-ignore
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { PromptTemplate } from "langchain/prompts";
2+
import * as vscode from "vscode";
3+
4+
export const getHighlightedTextDetails = (): {
5+
content: string;
6+
startLine: number;
7+
endLine: number;
8+
filePath: string;
9+
} | null => {
10+
// Get the active vscode text editor instance.
11+
let editor = vscode.window.activeTextEditor;
12+
13+
if (!editor) {
14+
return null; // If no editor is open, we'll return null.
15+
}
16+
17+
const selection = editor?.selection;
18+
19+
if (selection && !selection.isEmpty) {
20+
// Create a new Range object with the start and end of selected text in vscode document.
21+
let rangeSelectionText: vscode.Range = new vscode.Range(
22+
selection.start.line,
23+
selection.start.character,
24+
selection.end.line,
25+
selection.end.character
26+
);
27+
28+
// Get the text from selected lines in document using Range object we created above.
29+
let content = editor?.document.getText(rangeSelectionText) || "";
30+
31+
return {
32+
filePath: (editor && editor.document.uri.fsPath) || "",
33+
startLine: selection.start.line, // line number where the selected text starts from
34+
endLine: selection.end.line, // line number where the selected text ends to
35+
content: content, // The actual highlighted code/text in string format
36+
};
37+
} else {
38+
return null;
39+
}
40+
};
41+
42+
export const systemTemplate = `
43+
You are an AI Assistant who\`s a coding expert. Answer on below question.
44+
45+
Input format:
46+
- The provided code is the code that the user selected for this question, usually, it is relative to the question.
47+
- User question.
48+
49+
Instructions:
50+
- Answer in short form.
51+
- Don't answer, if you don't know the answer.
52+
- Don't explain why you did this change.
53+
- Only answer what the user asked.
54+
- If the code is not relative to the question, don't use it for the answer.
55+
- If the answer expects any code examples, please provide examples.
56+
57+
Rules for code in response:
58+
- Suggest only changes.
59+
- Provide only the necessary code.
60+
- Write as less as possible comments.
61+
`;
62+
63+
export const humanMessageWithCodePrompt = new PromptTemplate({
64+
inputVariables: ["highlightedCode", "question"],
65+
template: `Please provide an answer on this question using a provided code.
66+
67+
Provided Code:
68+
\`\`\`
69+
{highlightedCode}
70+
\`\`\`
71+
72+
Question: {question}
73+
`,
74+
});

src/common/completion/index.ts

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as vscode from "vscode";
22
import { randomUUID } from "crypto";
33
import { getPromptCompletion } from "../prompt";
4-
import { abortInterval, delay } from "../utils/intervals";
4+
import { abortInterval, delay } from "./utils/intervals";
5+
import { getAdditionalDocuments } from "./utils/getAdditionalDocuments";
56
import Logger from "../logger";
67
import { sendCompletionRequest } from "./localCompletion";
78
import { servers } from "../server";
@@ -23,6 +24,7 @@ export const getInlineCompletionProvider = (
2324
) => {
2425
let maxToken = 50;
2526
let expectedTime = 1000;
27+
2628
const provider: vscode.InlineCompletionItemProvider = {
2729
provideInlineCompletionItems: async (
2830
document,
@@ -32,15 +34,19 @@ export const getInlineCompletionProvider = (
3234
) => {
3335
const triggerAuto =
3436
context.triggerKind === vscode.InlineCompletionTriggerKind.Automatic;
37+
3538
const currentInlineSuggestModeAuto = state.workspace.get(
3639
"inlineSuggestModeAuto"
3740
);
41+
3842
if (currentInlineSuggestModeAuto !== true && triggerAuto === true) {
3943
return [];
4044
}
45+
4146
if (context.selectedCompletionInfo) {
4247
return [];
4348
}
49+
4450
const loggerCompletion = logCompletion();
4551

4652
loggerCompletion.info("Completion: started");
@@ -50,57 +56,39 @@ export const getInlineCompletionProvider = (
5056
loggerCompletion.info("Completion: canceled");
5157
return [];
5258
}
59+
5360
const { abortController, requestFinish } = abortInterval(token);
5461

5562
const modelType = triggerAuto
5663
? configuration.get("completion.autoMode")
5764
: configuration.get("completion.manuallyMode");
5865

59-
const serverUrl = configuration.get("cloud.use")
60-
? configuration.get("cloud.endpoint")
61-
: servers[modelType].serverUrl;
62-
63-
let additionalDocuments: vscode.TextDocument[] = [];
64-
65-
if (configuration.get("experimental.useopentabs")) {
66-
const additionalDocumentsUri = vscode.window.tabGroups.all
67-
.map((group) => group.tabs)
68-
.flat()
69-
.filter((tab) => !(tab.group.isActive && tab.isActive))
70-
.filter(
71-
(tab) =>
72-
tab.input &&
73-
"uri" in (tab.input as any) &&
74-
((tab.input as any).uri as vscode.Uri).scheme === "file"
75-
)
76-
.map((tab) => (tab.input as any).uri as vscode.Uri);
77-
additionalDocuments = await Promise.all(
78-
additionalDocumentsUri.map((uri) =>
79-
vscode.workspace.openTextDocument(uri)
80-
)
81-
);
82-
}
66+
const serverUrl = servers[modelType].serverUrl;
67+
68+
const additionalDocuments: vscode.TextDocument[] = configuration.get(
69+
"experimental.useopentabs"
70+
)
71+
? await getAdditionalDocuments()
72+
: [];
8373

8474
const prompt = await getPromptCompletion({
8575
activeDocument: document,
8676
additionalDocuments: additionalDocuments,
8777
position: position,
88-
maxTokenExpect:
89-
triggerAuto && !configuration.get("cloud.use") ? maxToken : 2000,
78+
maxTokenExpect: triggerAuto ? maxToken : 2000,
9079
url: serverUrl,
9180
});
9281

93-
const parameters =
94-
triggerAuto && !configuration.get("cloud.use")
95-
? {
96-
n_predict: 128,
97-
stop: ["\n"],
98-
}
99-
: {
100-
n_predict: 512,
101-
stop: [],
102-
temperature: 0.5,
103-
};
82+
const parameters = triggerAuto
83+
? {
84+
n_predict: 128,
85+
stop: ["\n"],
86+
}
87+
: {
88+
n_predict: 512,
89+
stop: [],
90+
temperature: 0.5,
91+
};
10492

10593
try {
10694
Logger.info(

0 commit comments

Comments
 (0)