Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"antlr4": "4.7.2",
"bootstrap": "4.4.1",
"chroma-js": "2.1.0",
"diff": "4.0.2",
"diff": "^4.0.2",
"diff2html": "^3.4.48",
"elementtree": "0.1.7",
"marked": "4.0.12",
"monaco-editor": "0.21.2",
Expand All @@ -16,6 +17,7 @@
"openai": "^4.30.0",
"path": "0.12.7",
"pluralize": "7.0.0",
"prismjs": "^1.29.0",
"rc-slider": "8.7.1",
"rc-tooltip": "4.0.0-alpha.3",
"react": "16.12.0",
Expand Down
143 changes: 114 additions & 29 deletions src/activeLLM/suggestFix.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,41 @@ export async function suggestFix(
violation,
exampleFilePath,
violationFilePath,
violationFileContent,
setState,
) {

const prompt = `Here is a design rule and its description: ${rule}
Here is a code example that follows this design rule: ${example}
The example file path is ${exampleFilePath}
Now, here is a code snippet that violates this design rule: ${violation}
The violated code's file path is ${violationFilePath}
Can you suggest a fix to make this violation follow the given design rule?
Generate code with surrounding code included that follows the design rule.
Be sure to maintain proper whitespace with \\t and \\n.
Give a brief explanation of your fix as well.
Ensure to include the fileName of where to insert the fix in the format Example.java.
Strictly output in JSON format. The JSON should have the following format:{"code": "...", "explanation": "...", "fileName": "..."}`;

//the following prompt is an older version. It is commented out because the one used right now is more
//concise and produces better output
/*const prompt = `Here is a design rule and its description: ${rule}
Here is a code example that follows this design rule: ${example}
The example file path is ${exampleFilePath}
Now, here is a code snippet that violates this design rule. ${violation}
The violated code's file path is ${violationFilePath}
Suggest a fix to make this violation follow the given design rule?
Generate code with surrounding code included that follows the design rule.
Be sure to maintain proper whitespace with \\t and \\n.
Give a brief explanation of your fix as well. Strictly output in JSON format.
Ensure that you include the fileName where the fix should be inserted at.
This should just be in the format Example.java
The JSON should have the following format:{"code": "...", "explanation": "...", "fileName": "..."}`;*/
const prompt = `You are assisting with enforcing the following design rule:
${rule}

Here is a code example that follows the rule:
${example}
Example file path: ${exampleFilePath}

<<<ORIGINAL_FILE_PATH>>>
${violationFilePath}
<<<END_ORIGINAL_FILE_PATH>>>

<<<ORIGINAL_FILE_CONTENT>>>
${violationFileContent}
<<<END_ORIGINAL_FILE_CONTENT>>>

<<<VIOLATION_SNIPPET>>>
${violation}
<<<END_VIOLATION_SNIPPET>>>

Rewrite the original file so it satisfies the rule while preserving every unrelated line verbatim. Constraints:
- Copy every existing package declaration, import statement, comment, Javadoc, and formatting exactly as provided unless a specific line must change to satisfy the rule.
- Do NOT delete or reorder imports; append new imports after the existing block if required.
- When you modify a line, change only the minimal portion needed; leave all other lines identical.
- Preserve indentation and whitespace on all untouched lines.

Respond strictly as JSON with the structure {\"modifiedFileContent\":\"...\", \"explanation\":\"...\", \"fileName\":\"...\"}.`;

let attempt = 1;
let success = false;
console.log("violation codde sent to chatGPT:");
console.log(violationFileContent);

while (attempt <= 3 && !success) {
try {
Expand All @@ -60,9 +63,12 @@ export async function suggestFix(
const stripped = suggestedSnippet.replace(/^`json|`json$/g, "").trim();
const parsedJSON = JSON.parse(stripped);

console.log("Solution from chatGPT:");
console.log(parsedJSON);

// sets the relevant state in the React component that made the request
// see ../ui/rulePanel.js for more details
setState({suggestedSnippet: parsedJSON["code"]});
setState({suggestedSnippet: parsedJSON["modifiedFileContent"]});
setState({snippetExplanation: parsedJSON["explanation"]});
setState({suggestionFileName: parsedJSON["fileName"]});

Expand All @@ -71,15 +77,94 @@ export async function suggestFix(
data: {
filePath: `${violationFilePath}`,
fileToChange: `${parsedJSON["fileName"]}`,
modifiedFileContent: `${parsedJSON["code"]}`,
explanation: `${parsedJSON["explanation"]}`,
modifiedFileContent: parsedJSON["modifiedFileContent"],
explanation: parsedJSON["explanation"],
originalFileContent: violationFileContent,
},
};

// set the modified content state, will be sent plugin
setState({llmModifiedFileContent: llmModifiedFileContent});

success = true;
return llmModifiedFileContent;
} catch (error) {
console.log(error);
success = false;
attempt++;
}
}
}



export async function editFix(fileContentToSendToGPT,conversationHistory,setState) {

console.log("CAME TO EDIT FIX");
//console.log(fileContentToSendToGPT);
//conversationHistory = {role:'user',content:conversationHistory};

// Create the additional prompt using the projectPath
const additionalPrompt = `You previously suggested the following fix (JSON snippet below). Integrate it into the provided file without removing unrelated lines.

<<<PREVIOUS_RESPONSE>>>
${conversationHistory}
<<<END_PREVIOUS_RESPONSE>>>

<<<ORIGINAL_FILE_CONTENT>>>
${fileContentToSendToGPT}
<<<END_ORIGINAL_FILE_CONTENT>>>

Rewrite the file so it satisfies the rule while preserving every existing package, import, comment, and formatting exactly as provided unless a line must change to satisfy the rule. Do not delete or reorder imports; only append new ones if required. Modify only the minimal code needed and keep all untouched lines verbatim.
Respond strictly as JSON with the structure {\"modifiedFileContent\":\"...\", \"explanation\":\"...\", \"fileName\":\"...\"}.`;
const continuedConversation = [ { role: "user", content: additionalPrompt }];

let attempt = 1;
let success = false;

while (attempt <= 3 && !success) {
try {
const apiKey = localStorage.getItem("OPENAI_API_KEY");
const openai = new OpenAI({
apiKey,
dangerouslyAllowBrowser: true,
});

// Send the continued conversation to OpenAI
const chatCompletion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
temperature: 0.75,
messages: continuedConversation,
});

const suggestedSnippet = chatCompletion.choices[0].message.content;
const stripped = suggestedSnippet.replace(/^`json|`json$/g, "").trim();
const parsedJSON = JSON.parse(stripped);

console.log(parsedJSON);

// Update state with new suggested snippet, explanation, and file name
setState((prevState) => ({
suggestedSnippet: parsedJSON["modifiedFileContent"],
snippetExplanation: parsedJSON["explanation"],
suggestionFileName: parsedJSON["fileName"],
llmModifiedFileContent: {
command: "LLM_MODIFIED_FILE_CONTENT",
data: {
filePath: `${parsedJSON["fileName"]}`, // Assuming the initial prompt contains the file path
fileToChange: `${parsedJSON["fileName"]}`,
modifiedFileContent: parsedJSON["modifiedFileContent"],
explanation: parsedJSON["explanation"],
originalFileContent: prevState?.originalFileContent ?? '',
},
},
}));

// Update conversation history in session storage
//saveConversationToSessionStorage(key, [...continuedConversation, { role: "assistant", content: suggestedSnippet }]);

success = true;
console.log("got second data from chatGPT");
} catch (error) {
console.log(error);
success = false;
Expand Down
4 changes: 4 additions & 0 deletions src/core/coreConstants.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export const webSocketSendMessage = {
send_info_for_edit_fix:"SEND_INFO_FOR_EDIT_FIX",
modified_rule_msg: "MODIFIED_RULE",
modified_tag_msg: "MODIFIED_TAG",
snippet_xml_msg: "XML_RESULT",
llm_modified_file_content: "LLM_MODIFIED_FILE_CONTENT",
converted_java_snippet_msg: "CONVERTED_JAVA_SNIPPET",
code_to_xml_msg: "EXPR_STMT",
new_rule_msg: "NEW_RULE",
new_tag_msg: "NEW_TAG",
send_llm_snippet_msg: "LLM_SNIPPET",

open_file_msg: "OPEN_FILE",

Expand All @@ -18,6 +21,7 @@ export const webSocketSendMessage = {
};

export const webSocketReceiveMessage = {
receive_content_for_edit_fix: "RECEIVE_CONTENT_FOR_EDIT_FIX",
xml_files_msg: "XML",
rule_table_msg: "RULE_TABLE",
tag_table_msg: "TAG_TABLE",
Expand Down
36 changes: 35 additions & 1 deletion src/core/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,40 @@ class Utilities {
tagInfo: data
};
break;

case webSocketSendMessage.send_llm_snippet_msg:
console.log("In command");
console.log(data);
messageJson.data={
code:data.suggestedSnippet,
explanation:data.snippetExplanation
}
break;

case webSocketSendMessage.send_info_for_edit_fix:
messageJson.data={
filePathOfSuggestedFix:data.data.fileToChange,
filePathOfViolation:data.data.filePath,
modifiedFileContent:data.data.modifiedFileContent
}
break;


case webSocketSendMessage.llm_modified_file_content:
if (!data.llmModifiedFileContent) {
console.warn('No LLM modified file content to send.');
return;
}

messageJson.data = {
filePath: data.llmModifiedFileContent.data.filePath,
explanation: data.llmModifiedFileContent.data.explanation,
fileToChange: data.llmModifiedFileContent.data.fileToChange,
modifiedFileContent: data.llmModifiedFileContent.data.modifiedFileContent,
originalFileContent: data.originalFileContent || data.llmModifiedFileContent.data.originalFileContent || '',
}

break;
case webSocketSendMessage.snippet_xml_msg:
messageJson.data = {
fileName: data.fileName,
Expand Down Expand Up @@ -246,4 +280,4 @@ class Utilities {

}

export default Utilities;
export default Utilities;
28 changes: 19 additions & 9 deletions src/core/webSocketManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import {Component} from "react";
import {connect} from "react-redux";


import {
receiveExpressionStatementXML,
ignoreFileChange, updateFilePath,
Expand Down Expand Up @@ -51,6 +52,7 @@ class WebSocketManager extends Component {

switch (message.command) {


case webSocketReceiveMessage.enter_chat_msg:
this.props.onLoadingGif(true);
break;
Expand Down Expand Up @@ -170,17 +172,25 @@ class WebSocketManager extends Component {

case webSocketReceiveMessage.file_change_in_ide_msg:
// data: "filePath"

let focusedFilePath = message.data;
if (!this.props.ignoreFileChange) {
this.props.onFilePathChange(focusedFilePath);
window.location.hash = `#/${hashConst.rulesForFile}/` + focusedFilePath.replace(/\//g, "%2F");
} else {
counter--;
if (counter === 0) {
this.props.onFalsifyIgnoreFile();
counter = 3;
}
console.log("File name: ");
console.log(focusedFilePath);
focusedFilePath = String(focusedFilePath);

if(!focusedFilePath.includes("edit_fix_window")){
if (!this.props.ignoreFileChange) {
this.props.onFilePathChange(focusedFilePath);
window.location.hash = `#/${hashConst.rulesForFile}/` + focusedFilePath.replace(/\//g, "%2F");
} else {
counter--;
if (counter === 0) {
this.props.onFalsifyIgnoreFile();
counter = 3;
}
}
}

break;

/* Mining Rules */
Expand Down
Loading