Skip to content

Commit 3f0f5a7

Browse files
committed
Add runtime error repair PR example
1 parent 3685d70 commit 3f0f5a7

2 files changed

Lines changed: 107 additions & 1 deletion

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import ai.autohand.sdk.sdk.Agent;
2+
import ai.autohand.sdk.sdk.AgentOptions;
3+
import ai.autohand.sdk.sdk.RunResult;
4+
import ai.autohand.sdk.types.Events;
5+
6+
/**
7+
* Runtime error to pull request.
8+
*
9+
* This example shows how an application can capture a runtime error and ask
10+
* Autohand to fix it instead of only logging it. Point AUTOHAND_TARGET_REPO at
11+
* the application repository that should receive the branch, commit, push, and
12+
* pull request.
13+
*
14+
* Run with:
15+
* AUTOHAND_TARGET_REPO=/path/to/app mvn compile exec:java -Dexec.mainClass="RuntimeErrorToPullRequest"
16+
*/
17+
public class RuntimeErrorToPullRequest {
18+
record Cart(double subtotal, Customer customer) {}
19+
record Customer(String loyaltyTier) {}
20+
21+
public static void main(String[] args) throws Exception {
22+
String targetRepo = getenvOrDefault("AUTOHAND_TARGET_REPO", ".");
23+
String cliPath = System.getenv("AUTOHAND_CLI_PATH");
24+
String model = System.getenv("AUTOHAND_MODEL");
25+
String capturedError = captureRuntimeError();
26+
27+
Agent agent = Agent.create(AgentOptions.builder()
28+
.cwd(targetRepo)
29+
.cliPath(cliPath)
30+
.model(model)
31+
.instructions(String.join("\n",
32+
"You are a QA engineering agent that turns production error reports into small repair pull requests.",
33+
"Reproduce the failure when the repository makes that possible.",
34+
"Fix the root cause, add or update a focused regression test, run the relevant validation command, commit the fix, push a branch, and create a pull request.",
35+
"Keep the pull request description concise and include the error signature, the fix summary, and the validation result."))
36+
.build());
37+
38+
try {
39+
var run = agent.send(String.join("\n",
40+
"A runtime error was captured by the application error boundary.",
41+
"Use this error report to repair the application automatically.",
42+
"",
43+
"Captured error:",
44+
"```text",
45+
capturedError,
46+
"```",
47+
"",
48+
"Expected user impact:",
49+
"A checkout session should still calculate a safe default discount when the customer object is missing.",
50+
"",
51+
"Please create a pull request with the fix."));
52+
53+
run.stream(event -> {
54+
switch (event) {
55+
case Events.MessageUpdateEvent message -> System.out.print(message.delta());
56+
case Events.ToolStartEvent tool -> System.out.println("\n[tool] " + tool.toolName());
57+
case Events.PermissionRequestEvent permission -> System.out.println("\n[permission] " + permission.tool() + ": " + permission.description());
58+
case Events.ErrorEvent error -> System.err.println("\n[error] " + error.message());
59+
default -> {}
60+
}
61+
});
62+
63+
RunResult result = run.waitForResult();
64+
System.out.println("\n\nRun " + result.id() + " " + result.status() + ".");
65+
} finally {
66+
agent.close();
67+
}
68+
}
69+
70+
static double checkoutDiscount(Cart cart) {
71+
try {
72+
if (cart.customer().loyaltyTier().equals("gold")) {
73+
return cart.subtotal() * 0.15;
74+
}
75+
return cart.subtotal() * 0.05;
76+
} catch (RuntimeException error) {
77+
throw new IllegalStateException("checkout discount failed: " + error.getMessage(), error);
78+
}
79+
}
80+
81+
static String captureRuntimeError() {
82+
try {
83+
checkoutDiscount(new Cart(129, null));
84+
} catch (Exception error) {
85+
return error + "\n" + stackTrace(error);
86+
}
87+
88+
return String.join("\n",
89+
"IllegalStateException: checkout discount failed: Cannot invoke Customer.loyaltyTier() because customer is null",
90+
" at checkout.Discounts.checkoutDiscount(Discounts.java:42)",
91+
" at checkout.Session.createCheckoutSession(Session.java:88)",
92+
"Request: POST /checkout",
93+
"Payload: {\"subtotal\":129,\"customer\":null}");
94+
}
95+
96+
static String stackTrace(Exception error) {
97+
java.io.StringWriter writer = new java.io.StringWriter();
98+
error.printStackTrace(new java.io.PrintWriter(writer));
99+
return writer.toString();
100+
}
101+
102+
static String getenvOrDefault(String name, String fallback) {
103+
String value = System.getenv(name);
104+
return value == null || value.isBlank() ? fallback : value;
105+
}
106+
}

src/test/java/ai/autohand/sdk/ExampleCompileTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void allExamplesCompileAgainstPublishedApi() throws Exception {
2727
.toList();
2828
}
2929

30-
assertEquals(27, examples.size(), "Keep this aligned with the TypeScript example set.");
30+
assertEquals(28, examples.size(), "Keep this aligned with the TypeScript example set.");
3131

3232
var compiler = ToolProvider.getSystemJavaCompiler();
3333
assertNotNull(compiler, "Run tests with a JDK, not a JRE.");

0 commit comments

Comments
 (0)