refactor: Improve logging in Llama class

This commit is contained in:
Simon Larsen
2024-07-09 12:54:49 +01:00
parent 74d4a6545e
commit 5251b93fc9
7 changed files with 236 additions and 67 deletions

View File

@@ -30,7 +30,7 @@ jobs:
# Run Reliability Copilot in Doker Container
- name: Run Copilot
run: |
docker run --rm \
docker run --rm oneuptime/copilot:test \
-e ONEUPTIME_URL='https://test.oneuptime.com' \
-e ONEUPTIME_REPOSITORY_SECRET_KEY=${{ secrets.COPILOT_ONEUPTIME_REPOSITORY_SECRET_KEY }} \
-e CODE_REPOSITORY_PASSWORD=${{ github.token }} \

View File

@@ -12,6 +12,90 @@ export default class Text {
return hex;
}
public static getFirstWord(text: string): string {
if (!text || text.length === 0) {
return text;
}
const textArr: Array<string> = text.split(" ");
let firstIndex: number = 0;
while (firstIndex < textArr.length && !textArr[firstIndex]) {
firstIndex++;
}
return textArr[firstIndex] || text;
}
public static getLastWord(text: string): string {
if (!text || text.length === 0) {
return text;
}
const textArr: Array<string> = text.split(" ");
let lastIndex: number = textArr.length - 1;
while (lastIndex >= 0 && !textArr[lastIndex]) {
lastIndex--;
}
return textArr[lastIndex] || text;
}
public static trimStartUntilThisWord(text: string, word: string): string {
if (!text || text.length === 0) {
return text;
}
const index: number = text.indexOf(word);
if (index === -1) {
return text;
}
return text.substring(index);
}
public static trimUpQuotesFromStartAndEnd(text: string): string {
if (!text || text.length === 0) {
return text;
}
if (text.startsWith('"') && !text.endsWith('"')) {
text = text.substring(1);
}
if (text.endsWith('"') && !text.startsWith('"')) {
text = text.substring(0, text.length - 1);
}
// check for single quotes
if (text.startsWith("'") && !text.endsWith("'")) {
text = text.substring(1);
}
if (text.endsWith("'") && !text.startsWith("'")) {
text = text.substring(0, text.length - 1);
}
return text;
}
public static trimEndUntilThisWord(text: string, word: string): string {
if (!text || text.length === 0) {
return text;
}
const index: number = text.lastIndexOf(word);
if (index === -1) {
return text;
}
return text.substring(0, index + word.length);
}
public static isBase64(text: string): boolean {
const regex: RegExp = /^[a-zA-Z0-9+/]*={0,2}$/;
return regex.test(text);

View File

@@ -349,6 +349,8 @@ export default class API {
headers: finalHeaders,
data: finalBody,
});
break;
} catch (e) {
if (currentRetry <= maxRetries) {
if (exponentialBackoff) {

View File

@@ -103,13 +103,7 @@ export default class CodeRepositoryUtil {
`${data.repoPath}/${data.filePath}`,
);
const command: string = `echo "${data.content}" > ${totalPath}`;
logger.debug("Executing command: " + command);
const stdout: string = await Execute.executeCommand(command);
logger.debug(stdout);
await LocalFile.write(totalPath, data.content);
}
public static async createDirectory(data: {
@@ -120,13 +114,7 @@ export default class CodeRepositoryUtil {
`${data.repoPath}/${data.directoryPath}`,
);
const command: string = `mkdir ${totalPath}`;
logger.debug("Executing command: " + command);
const stdout: string = await Execute.executeCommand(command);
logger.debug(stdout);
await LocalFile.makeDirectory(totalPath);
}
public static async deleteFile(data: {
@@ -137,13 +125,7 @@ export default class CodeRepositoryUtil {
`${data.repoPath}/${data.filePath}`,
);
const command: string = `rm ${totalPath}`;
logger.debug("Executing command: " + command);
const stdout: string = await Execute.executeCommand(command);
logger.debug(stdout);
await LocalFile.deleteFile(totalPath);
}
public static async deleteDirectory(data: {

View File

@@ -12,6 +12,45 @@ export default class LocalFile {
return fileExtention[fileExtention.length - 1]?.toLowerCase() || "";
}
public static async deleteFile(filePath: string): Promise<void> {
if ((await this.doesFileExist(filePath)) === false) {
return;
}
return new Promise(
(resolve: VoidFunction, reject: PromiseRejectErrorFunction) => {
fs.unlink(filePath, (err: Error | null) => {
if (err) {
return reject(err);
}
resolve();
});
},
);
}
public static async doesFileExist(path: string): Promise<boolean> {
return new Promise(
(
resolve: (exists: boolean) => void,
reject: PromiseRejectErrorFunction,
) => {
fs.stat(path, (err: Error | null, stats: fs.Stats) => {
if (err) {
if ((err as any).code === "ENOENT") {
return resolve(false);
}
return reject(err);
}
if (stats.isFile()) {
return resolve(true);
}
return resolve(false);
});
},
);
}
public static async doesDirectoryExist(path: string): Promise<boolean> {
return new Promise(
(

View File

@@ -95,7 +95,7 @@ export default class CopilotActionBase {
}
public async getPullRequestTitle(data: CopilotProcess): Promise<string> {
return `OneUptime Copilot: ${this.copilotActionType} on ${data.input.currentFilePath}`;
return `[OneUptime Copilot] ${this.copilotActionType} on ${data.input.currentFilePath}`;
}
public async getPullRequestBody(data: CopilotProcess): Promise<string> {

View File

@@ -8,6 +8,7 @@ import CodeRepositoryUtil from "../../Utils/CodeRepository";
import ServiceLanguage from "Common/Types/ServiceCatalog/ServiceLanguage";
import { CopilotPromptResult } from "../LLM/LLMBase";
import CodeRepositoryFile from "CommonServer/Utils/CodeRepository/CodeRepositoryFile";
import Text from "Common/Types/Text";
export default class ImproveComments extends CopilotActionBase {
public isRequirementsMet: boolean = false;
@@ -22,11 +23,81 @@ export default class ImproveComments extends CopilotActionBase {
return Promise.resolve(this.isRequirementsMet);
}
public async commentCodePart(options: {
data: CopilotProcess;
codePart: string;
currentRetryCount: number;
maxRetryCount: number;
}): Promise<{
newCode: string;
isWellCommented: boolean;
}> {
let isWellCommented: boolean = true;
const codePart: string = options.codePart;
const data: CopilotProcess = options.data;
const actionPrompt: CopilotActionPrompt = await this.getPrompt(
data,
codePart,
);
const copilotResult: CopilotPromptResult =
await this.askCopilot(actionPrompt);
const newCodePart: string = await this.cleanupCode({
inputCode: codePart,
outputCode: copilotResult.output as string,
});
if (!(await this.isFileAlreadyWellCommented(newCodePart))) {
isWellCommented = false;
}
const validationPrompt: CopilotActionPrompt =
await this.getValidationPrompt({
oldCode: codePart,
newCode: newCodePart,
});
const validationResponse: CopilotPromptResult =
await this.askCopilot(validationPrompt);
const didPassValidation: boolean =
await this.didPassValidation(validationResponse);
if (
!didPassValidation &&
options.currentRetryCount < options.maxRetryCount
) {
return await this.commentCodePart({
data: data,
codePart: codePart,
currentRetryCount: options.currentRetryCount + 1,
maxRetryCount: options.maxRetryCount,
});
}
if (!didPassValidation) {
return {
newCode: codePart,
isWellCommented: false,
};
}
return {
newCode: newCodePart,
isWellCommented: isWellCommented,
};
}
public override async onExecutionStep(
data: CopilotProcess,
): Promise<CopilotProcess> {
// Action Prompt
debugger;
const codeParts: string[] = await this.splitInputCode({
copilotProcess: data,
itemSize: 500,
@@ -35,44 +106,23 @@ export default class ImproveComments extends CopilotActionBase {
let newContent: string = "";
let isWellCommented: boolean = true;
let didPassFileValidation: boolean = false;
for (const codePart of codeParts) {
const actionPrompt: CopilotActionPrompt = await this.getPrompt(
data,
codePart,
);
const copilotResult: CopilotPromptResult =
await this.askCopilot(actionPrompt);
const newCodePart: string = await this.cleanup({
inputCode: codePart,
outputCode: copilotResult.output as string,
const codePartResult: {
newCode: string;
isWellCommented: boolean;
} = await this.commentCodePart({
data: data,
codePart: codePart,
currentRetryCount: 0,
maxRetryCount: 3,
});
if (!(await this.isFileAlreadyWellCommented(newCodePart))) {
if (!codePartResult.isWellCommented) {
isWellCommented = false;
}
const validationPrompt: CopilotActionPrompt =
await this.getValidationPrompt({
oldCode: codePart,
newCode: newCodePart,
});
const validationResponse: CopilotPromptResult =
await this.askCopilot(validationPrompt);
const didPassValidation: boolean =
await this.didPassValidation(validationResponse);
if (!didPassValidation) {
newContent = codePart;
break;
newContent += codePartResult.newCode + "\n";
} else {
didPassFileValidation = true;
newContent += newCodePart + "\n";
newContent += codePart + "\n";
}
}
@@ -83,17 +133,13 @@ export default class ImproveComments extends CopilotActionBase {
newContent = newContent.trim();
if (didPassFileValidation) {
// add to result.
data.result.files[data.input.currentFilePath] = {
...data.input.files[data.input.currentFilePath],
fileContent: newContent,
} as CodeRepositoryFile;
this.isRequirementsMet = true;
return data;
}
// add to result.
data.result.files[data.input.currentFilePath] = {
...data.input.files[data.input.currentFilePath],
fileContent: newContent,
} as CodeRepositoryFile;
this.isRequirementsMet = true;
return data;
}
@@ -164,7 +210,7 @@ export default class ImproveComments extends CopilotActionBase {
data.input.currentFilePath
]?.fileLanguage as ServiceLanguage;
const prompt: string = `Please improve the comments in this code. Please only comment code that is hard to understand.
const prompt: string = `Please improve the comments in this code. Please only add minimal comments and comment code which is hard to understand. Please add comments in new line and do not add inline comments.
If you think the code is already well commented, please reply with the following text:
--all-good--
@@ -199,7 +245,7 @@ export default class ImproveComments extends CopilotActionBase {
return systemPrompt;
}
public async cleanup(data: {
public async cleanupCode(data: {
inputCode: string;
outputCode: string;
}): Promise<string> {
@@ -221,6 +267,22 @@ export default class ImproveComments extends CopilotActionBase {
// get first line of input code.
const firstWordOfInputCode: string = Text.getFirstWord(data.inputCode);
extractedCode = Text.trimStartUntilThisWord(
extractedCode,
firstWordOfInputCode,
);
const lastWordOfInputCode: string = Text.getLastWord(data.inputCode);
extractedCode = Text.trimEndUntilThisWord(
extractedCode,
lastWordOfInputCode,
);
extractedCode = Text.trimUpQuotesFromStartAndEnd(extractedCode);
// check for quotes.
return extractedCode;
}
}