mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor: Improve logging in Llama class
This commit is contained in:
2
.github/workflows/reliability-copilot.yml
vendored
2
.github/workflows/reliability-copilot.yml
vendored
@@ -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 }} \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -349,6 +349,8 @@ export default class API {
|
||||
headers: finalHeaders,
|
||||
data: finalBody,
|
||||
});
|
||||
|
||||
break;
|
||||
} catch (e) {
|
||||
if (currentRetry <= maxRetries) {
|
||||
if (exponentialBackoff) {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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(
|
||||
(
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user