Skip to content

Commit 432ab8a

Browse files
Copilotbrunoborges
andcommitted
Add static factory methods to PreToolUseHookOutput record
Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>
1 parent b58904b commit 432ab8a

File tree

6 files changed

+69
-31
lines changed

6 files changed

+69
-31
lines changed

src/main/java/com/github/copilot/sdk/json/PreToolUseHookOutput.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,56 @@ public record PreToolUseHookOutput(@JsonProperty("permissionDecision") String pe
2929
@JsonProperty("modifiedArgs") JsonNode modifiedArgs,
3030
@JsonProperty("additionalContext") String additionalContext,
3131
@JsonProperty("suppressOutput") Boolean suppressOutput) {
32+
33+
/**
34+
* Creates an output that allows the tool to execute.
35+
*
36+
* @return a new PreToolUseHookOutput with permission decision "allow"
37+
*/
38+
public static PreToolUseHookOutput allow() {
39+
return new PreToolUseHookOutput("allow", null, null, null, null);
40+
}
41+
42+
/**
43+
* Creates an output that denies the tool execution.
44+
*
45+
* @return a new PreToolUseHookOutput with permission decision "deny"
46+
*/
47+
public static PreToolUseHookOutput deny() {
48+
return new PreToolUseHookOutput("deny", null, null, null, null);
49+
}
50+
51+
/**
52+
* Creates an output that denies the tool execution with a reason.
53+
*
54+
* @param reason
55+
* the reason for denying the tool execution
56+
* @return a new PreToolUseHookOutput with permission decision "deny" and reason
57+
*/
58+
public static PreToolUseHookOutput deny(String reason) {
59+
return new PreToolUseHookOutput("deny", reason, null, null, null);
60+
}
61+
62+
/**
63+
* Creates an output that asks for user confirmation before executing the tool.
64+
*
65+
* @return a new PreToolUseHookOutput with permission decision "ask"
66+
*/
67+
public static PreToolUseHookOutput ask() {
68+
return new PreToolUseHookOutput("ask", null, null, null, null);
69+
}
70+
71+
/**
72+
* Creates an output with modified tool arguments.
73+
*
74+
* @param permissionDecision
75+
* "allow", "deny", or "ask"
76+
* @param modifiedArgs
77+
* the modified tool arguments
78+
* @return a new PreToolUseHookOutput with the specified permission and modified
79+
* arguments
80+
*/
81+
public static PreToolUseHookOutput withModifiedArgs(String permissionDecision, JsonNode modifiedArgs) {
82+
return new PreToolUseHookOutput(permissionDecision, null, modifiedArgs, null, null);
83+
}
3284
}

src/main/java/com/github/copilot/sdk/json/SessionHooks.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* <pre>{@code
1616
* var hooks = new SessionHooks().setOnPreToolUse((input, invocation) -> {
1717
* System.out.println("Tool being called: " + input.getToolName());
18-
* return CompletableFuture.completedFuture(new PreToolUseHookOutput("allow", null, null, null, null));
18+
* return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
1919
* }).setOnPostToolUse((input, invocation) -> {
2020
* System.out.println("Tool result: " + input.getToolResult());
2121
* return CompletableFuture.completedFuture(null);

src/site/markdown/advanced.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,7 @@ Intercept tool execution and session lifecycle events using hooks.
364364
var hooks = new SessionHooks()
365365
.setOnPreToolUse((input, invocation) -> {
366366
System.out.println("Tool: " + input.getToolName());
367-
return CompletableFuture.completedFuture(
368-
new PreToolUseHookOutput("allow", null, null, null, null)
369-
);
367+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
370368
})
371369
.setOnPostToolUse((input, invocation) -> {
372370
System.out.println("Result: " + input.getToolResult());

src/site/markdown/hooks.md

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ Register hooks when creating a session:
2626
var hooks = new SessionHooks()
2727
.setOnPreToolUse((input, invocation) -> {
2828
System.out.println("Tool: " + input.getToolName());
29-
return CompletableFuture.completedFuture(
30-
new PreToolUseHookOutput("allow", null, null, null, null)
31-
);
29+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
3230
})
3331
.setOnPostToolUse((input, invocation) -> {
3432
System.out.println("Result: " + input.getToolResult());
@@ -83,21 +81,17 @@ var hooks = new SessionHooks()
8381
// Block file deletion
8482
if (tool.equals("delete_file")) {
8583
return CompletableFuture.completedFuture(
86-
new PreToolUseHookOutput("deny", "File deletion is not allowed", null, null, null)
84+
PreToolUseHookOutput.deny("File deletion is not allowed")
8785
);
8886
}
8987

9088
// Require confirmation for shell commands
9189
if (tool.equals("run_terminal_cmd")) {
92-
return CompletableFuture.completedFuture(
93-
new PreToolUseHookOutput("ask", null, null, null, null)
94-
);
90+
return CompletableFuture.completedFuture(PreToolUseHookOutput.ask());
9591
}
9692

9793
// Allow everything else
98-
return CompletableFuture.completedFuture(
99-
new PreToolUseHookOutput("allow", null, null, null, null)
100-
);
94+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
10195
});
10296
```
10397

@@ -116,12 +110,10 @@ var hooks = new SessionHooks()
116110
modifiedArgs.set("query", input.getToolArgs().get("query"));
117111

118112
return CompletableFuture.completedFuture(
119-
new PreToolUseHookOutput("allow", null, modifiedArgs, null, null)
113+
PreToolUseHookOutput.withModifiedArgs("allow", modifiedArgs)
120114
);
121115
}
122-
return CompletableFuture.completedFuture(
123-
new PreToolUseHookOutput("allow", null, null, null, null)
124-
);
116+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
125117
});
126118
```
127119

@@ -310,13 +302,11 @@ public class HooksExample {
310302
// Deny dangerous operations
311303
if (input.getToolName().contains("delete")) {
312304
return CompletableFuture.completedFuture(
313-
new PreToolUseHookOutput("deny", "Deletion not allowed", null, null, null)
305+
PreToolUseHookOutput.deny("Deletion not allowed")
314306
);
315307
}
316308

317-
return CompletableFuture.completedFuture(
318-
new PreToolUseHookOutput("allow", null, null, null, null)
319-
);
309+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
320310
})
321311

322312
// Logging: track tool results
@@ -383,14 +373,12 @@ To handle errors gracefully in your hooks:
383373
.setOnPreToolUse((input, invocation) -> {
384374
try {
385375
// Your logic here
386-
return CompletableFuture.completedFuture(
387-
new PreToolUseHookOutput("allow", null, null, null, null)
388-
);
376+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
389377
} catch (Exception e) {
390378
logger.error("Hook error", e);
391379
// Fail-safe: deny if something goes wrong
392380
return CompletableFuture.completedFuture(
393-
new PreToolUseHookOutput("deny", "Internal error", null, null, null)
381+
PreToolUseHookOutput.deny("Internal error")
394382
);
395383
}
396384
})

src/test/java/com/github/copilot/sdk/HooksTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ void testInvokePreToolUseHookWhenModelRunsATool() throws Exception {
7070
var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
7171
preToolUseInputs.add(input);
7272
assertEquals(sessionIdHolder[0], invocation.getSessionId());
73-
return CompletableFuture.completedFuture(new PreToolUseHookOutput("allow", null, null, null, null));
73+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
7474
}));
7575

7676
try (CopilotClient client = ctx.createClient()) {
@@ -149,7 +149,7 @@ void testInvokeBothHooksForSingleToolCall() throws Exception {
149149

150150
var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
151151
preToolUseInputs.add(input);
152-
return CompletableFuture.completedFuture(new PreToolUseHookOutput("allow", null, null, null, null));
152+
return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
153153
}).setOnPostToolUse((input, invocation) -> {
154154
postToolUseInputs.add(input);
155155
return CompletableFuture.completedFuture(null);
@@ -195,7 +195,7 @@ void testDenyToolExecutionWhenPreToolUseReturnsDeny() throws Exception {
195195
var config = new SessionConfig().setHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> {
196196
preToolUseInputs.add(input);
197197
// Deny all tool calls
198-
return CompletableFuture.completedFuture(new PreToolUseHookOutput("deny", null, null, null, null));
198+
return CompletableFuture.completedFuture(PreToolUseHookOutput.deny());
199199
}));
200200

201201
try (CopilotClient client = ctx.createClient()) {

src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,8 @@ void hooksInvokeWithNullOutput() throws Exception {
468468
@Test
469469
void hooksInvokeWithNonNullOutput() throws Exception {
470470
CopilotSession session = createSession("s1");
471-
session.registerHooks(new SessionHooks().setOnPreToolUse((input, invocation) -> CompletableFuture
472-
.completedFuture(new PreToolUseHookOutput("allow", null, null, null, null))));
471+
session.registerHooks(new SessionHooks().setOnPreToolUse(
472+
(input, invocation) -> CompletableFuture.completedFuture(PreToolUseHookOutput.allow())));
473473

474474
ObjectNode params = MAPPER.createObjectNode();
475475
params.put("sessionId", "s1");

0 commit comments

Comments
 (0)