Skip to content

Commit

Permalink
Merge branch 'XiaoMi:multi_agent' into multi_agent
Browse files Browse the repository at this point in the history
  • Loading branch information
HawickMason authored Jan 6, 2025
2 parents e483e18 + 9d59a94 commit 3b57189
Show file tree
Hide file tree
Showing 18 changed files with 633 additions and 132 deletions.
4 changes: 2 additions & 2 deletions jcommon/hive/src/main/java/run/mone/hive/actions/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class Action {

protected LLM llm;

protected BiFunction<ActionReq, Action, String> function = (req, action) -> this.getClass().getName();
protected BiFunction<ActionReq, Action, Message> function = (req, action) -> Message.builder().content(this.getClass().getName()).build();

@ToString.Exclude
private Role role;
Expand All @@ -34,7 +34,7 @@ public Action(String name, String description) {
}

public CompletableFuture<Message> run(ActionReq req) {
return CompletableFuture.supplyAsync(() -> Message.builder().role(req.getRole().getName()).content(this.function.apply(req, this)).build());
return CompletableFuture.supplyAsync(() -> Message.builder().role(req.getRole().getName()).content(this.function.apply(req, this).getContent()).build());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public class AnalyzeArchitecture extends Action {
@Override
public CompletableFuture<Message> run(ActionReq req) {
log.info("AnalyzeArchitecture");
return CompletableFuture.supplyAsync(() -> Message.builder().sendTo(Lists.newArrayList("Design")).role(req.getRole().getProfile()).content(this.function.apply(req, this)).build());
return CompletableFuture.supplyAsync(() -> Message.builder().sendTo(Lists.newArrayList("Design")).role(req.getRole().getProfile()).content(this.function.apply(req, this).getContent()).build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ public class WriteCode extends Action {
@Override
public CompletableFuture<Message> run(ActionReq req) {
log.info("WriteCode");
return CompletableFuture.supplyAsync(() -> Message.builder().role(req.getRole().getProfile()).content(this.function.apply(req, this)).build());
return CompletableFuture.supplyAsync(() -> {
Message msg = this.function.apply(req, this);
msg.setRole(req.getRole().getName());
return msg;
});
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public class WriteDesign extends Action {
@Override
public CompletableFuture<Message> run(ActionReq req) {
log.info("WriteDesign");
return CompletableFuture.supplyAsync(() -> Message.builder().role(req.getRole().getProfile()).sendTo(Lists.newArrayList("Engineer")).content(this.function.apply(req, this)).build());
return CompletableFuture.supplyAsync(() -> Message.builder().role(req.getRole().getProfile()).sendTo(Lists.newArrayList("Engineer")).content(this.function.apply(req, this).getContent()).build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,128 +3,70 @@
import com.google.common.collect.ImmutableMap;
import run.mone.hive.actions.Action;
import run.mone.hive.common.AiTemplate;
import run.mone.hive.schema.Message;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;


public class ExecutePythonCode extends Action {


private final String prompt = """
You are a Python code executor. Your task is to execute the following Python code:
${code}
The code should be executed with the following parameters:
${params}
Please provide the execution result without any additional explanations. Wrap the result in <result></result> tags.
""";

private final String paramGenerationPrompt = """
You are an AI assistant specialized in analyzing Python code and generating appropriate test parameters. Your task is to examine the following Python code and suggest suitable parameters for testing:
You are a Python code executor. Your task is to generate a single line of Python code that executes the following function with appropriate parameters:
${code}
Please provide a set of test parameters that will effectively exercise the main functionality of this code. Consider the following guidelines:
Generate a line of code that calls the main function with suitable parameters and prints the result.
The line should be in the format: print(function_name(param1, param2, ...))
1. Identify the main function or entry point of the code.
2. Determine the expected input types (e.g., integers, strings, lists, dictionaries).
3. Include edge cases and typical use cases in your parameter suggestions.
4. If the code requires specific formats (e.g., date strings, file paths), provide examples that match those formats.
5. If the code interacts with external resources (e.g., files, APIs), suggest mock data or placeholders.
Provide only the generated line of code without any additional explanations.
Format your response as a Python dictionary or a list of arguments, depending on how the main function accepts input. For example:
{"param1": value1, "param2": value2} or [arg1, arg2, arg3]
Provide only the parameter suggestions without any additional explanation.
example:
print(sun(11,22))
""";


public ExecutePythonCode() {
setFunction((req, action) -> {
String code = req.getMessage().getContent();
String params = generateParameters(code);
String renderedPrompt = AiTemplate.renderTemplate(prompt, ImmutableMap.of(
"code", code,
"params", params
"code", code
));
String exeCmd = llm.chat(renderedPrompt);

String result = null;
try {
result = executePythonCode(code, params);
result = executePythonCode(code + "\n" + exeCmd).getContent();
} catch (Exception e) {
throw new RuntimeException(e);
}
return "<result>" + result + "</result>";
return Message.builder().content(result).build();
});
}

private String generateParameters(String code) {
String promptForParams = AiTemplate.renderTemplate(paramGenerationPrompt, ImmutableMap.of(
"code", code
));
// Use LLMProvider to generate parameters
return llm.chat(promptForParams);
}

private String executePythonCode(String code, String params) throws Exception {
// Create a temporary file to store the Python code
Path tempFile = Files.createTempFile("python_code_", ".py");


Files.write(tempFile, code.getBytes());

// Prepare the command to execute Python code
ProcessBuilder processBuilder = new ProcessBuilder("python3", tempFile.toString());
processBuilder.redirectErrorStream(true);

// Set the working directory to the user's home directory
processBuilder.directory(new File(System.getProperty("user.home")));
// Start the process
StringBuilder output = new StringBuilder();
int exitCode = -1;
Process process = processBuilder.start();
// Read the output


// Read the output
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
//写一段代码 调用 python ```$code``` 执行代码,并且捕获输出如果有错误也包含错误(class)
public Message executePythonCode(String code) {
try {
ProcessBuilder processBuilder = new ProcessBuilder("python", "-c", code);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
}

// Wait for the process to complete
boolean completed = process.waitFor(30, TimeUnit.SECONDS);

// Delete the temporary file
Files.delete(tempFile);
if (!completed) {
process.destroyForcibly();
output.append("Error: Python code execution timed out after 30 seconds.");
} else {
exitCode = process.exitValue();
int exitCode = process.waitFor();
if (exitCode != 0) {
output.append("Error: Python code execution failed with exit code: ")
.append(exitCode)
.append("\n");
throw new RuntimeException("Python code execution failed with exit code " + exitCode);
}
return Message.builder().content(output.toString().trim()).build();
} catch (Exception e) {
return Message.builder().content(e.getMessage()).build();
}
String result = output.toString().trim();
if (result.isEmpty()) {
result = "No output or error message received.";
}
return result;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
package run.mone.hive.actions.python;

import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import run.mone.hive.actions.Action;
import run.mone.hive.common.AiTemplate;
import run.mone.hive.schema.Message;
import run.mone.hive.utils.PythonExecutor;

import java.util.regex.Matcher;
Expand All @@ -29,58 +32,29 @@ public FixPythonBug() {
this.pythonExecutor = new PythonExecutor();
setFunction((req, action) -> {
String buggyCode = req.getMessage().getContent();
JsonObject obj = new JsonParser().parse(buggyCode).getAsJsonObject();
String fixedCode = null;
try {
fixedCode = fixBug(buggyCode);
fixedCode = fixBug(obj.get("code").getAsString(), obj.get("error").getAsString());
} catch (Exception e) {
throw new RuntimeException(e);
}
return "<code>" + fixedCode + "</code>";
return Message.builder().content(fixedCode).build();
});
}

private String fixBug(String buggyCode) throws Exception {
String params = generateParameters(buggyCode);
String executionResult = pythonExecutor.executePythonCode(buggyCode, params);

if (!executionResult.toLowerCase().contains("error")) {
return buggyCode; // No error, return original code
}
private String fixBug(String buggyCode, String error) throws Exception {


String renderedPrompt = AiTemplate.renderTemplate(bugFixPrompt, ImmutableMap.of(
"code", buggyCode,
"error", executionResult
"error", error
));

String fixedCodeWithTags = llm.chat(renderedPrompt);
return extractCodeFromTags(fixedCodeWithTags);
}

private String generateParameters(String code) {
// Reuse the parameter generation logic from ExecutePythonCode
String paramGenerationPrompt = """
You are an AI assistant specialized in analyzing Python code and generating appropriate test parameters. Your task is to examine the following Python code and suggest suitable parameters for testing:
${code}
Please provide a set of test parameters that will effectively exercise the main functionality of this code. Consider the following guidelines:
1. Identify the main function or entry point of the code.
2. Determine the expected input types (e.g., integers, strings, lists, dictionaries).
3. Include edge cases and typical use cases in your parameter suggestions.
4. If the code requires specific formats (e.g., date strings, file paths), provide examples that match those formats.
5. If the code interacts with external resources (e.g., files, APIs), suggest mock data or placeholders.
Format your response as a Python dictionary or a list of arguments, depending on how the main function accepts input. For example:
{"param1": value1, "param2": value2} or [arg1, arg2, arg3]
Provide only the parameter suggestions without any additional explanation.
""";

String promptForParams = AiTemplate.renderTemplate(paramGenerationPrompt, ImmutableMap.of("code", code));
return llm.chat(promptForParams);
}

private String extractCodeFromTags(String codeWithTags) {
Pattern pattern = Pattern.compile("<code>(.*?)</code>", Pattern.DOTALL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import com.google.common.collect.ImmutableMap;
import run.mone.hive.actions.WriteCode;
import run.mone.hive.common.AiTemplate;
import run.mone.hive.common.StreamingXmlParser;
import run.mone.hive.common.XmlParserCallbackAdapter;
import run.mone.hive.schema.Message;
import run.mone.hive.schema.MetaKey;
import run.mone.hive.schema.MetaValue;

import java.util.ArrayList;
import java.util.List;

/**
* @author [email protected]
Expand All @@ -15,25 +23,46 @@ public class WritePythonCode extends WriteCode {
${requirements}
Please provide only the function implementation without any additional explanations. Wrap the code in <code></code> tags.
Please provide only the function implementation without any additional explanations. Wrap the code in <boltAction></boltAction> tags.
Here's an example of a sum function:
<code>
<boltAction>
def execute(params):
a = params.get('a', 0)
b = params.get('b', 0)
return a + b
</code>
</boltAction>
Now, please implement the function based on the given requirements.
""";

public WritePythonCode() {
setName("WritePythonCode");
setDescription("");
setFunction((req, action) -> {
String message = req.getMessage().getContent();
String str = AiTemplate.renderTemplate(prompt, ImmutableMap.of("requirements", message));
return this.llm.chat(str);
List<String> codeList = new ArrayList<>();
StringBuilder sb = new StringBuilder();
new StreamingXmlParser(new XmlParserCallbackAdapter() {
@Override
public void onActionStart(String type, String subType, String filePath) {
sb.setLength(0);
}

@Override
public void onActionEnd() {
codeList.add(sb.toString());
sb.setLength(0);
}

@Override
public void onContentChar(char c) {
sb.append(c);
}
}).append(str);
return Message.builder().content(this.llm.chat(str)).meta(ImmutableMap.of(MetaKey.builder().key("code").build(), MetaValue.builder().value(codeList).build())).build();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package run.mone.hive.common;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author [email protected]
* @date 11/25/24 4:00 PM
*/
public enum CustomStreamTag {

UNKNOWN(0, "unknown"),
ACTION(1, "boltAction"),
ARTIFACT(2, "boltArtifact");

private final int code;
private final String tagName;

private static final Map<Integer, CustomStreamTag> valMap = Arrays.stream(values()).collect(Collectors.toMap(CustomStreamTag::getCode, Function.identity()));

private static final Map<String, CustomStreamTag> nameMap = Arrays.stream(values()).collect(Collectors.toMap(CustomStreamTag::getTagName, Function.identity()));

CustomStreamTag(int code, String tagName) {
this.code = code;
this.tagName = tagName;
}

public int getCode() {
return code;
}

public String getTagName() {
return tagName;
}

public static CustomStreamTag getTagByName(String tagName) {
return nameMap.getOrDefault(tagName, UNKNOWN);
}

public static boolean isValidTagName(String tagName) {
return !UNKNOWN.getTagName().equals(tagName) && nameMap.containsKey(tagName);
}
}
Loading

0 comments on commit 3b57189

Please sign in to comment.